[Java · 初窥门径] 变量 & 常量

🌟 想系统化学习 Java 编程?看看这个:[编程基础] Java · 学习手册

0x01:变量 & 常量 —— 概念引入

无论是使用 Java 还是其他编程语言,我们都需要对数据进行处理。那么这些数据应该存储到什么地方呢?从编程的角度来看,就是存储到变量和常量中。变量和常量,它们相当于就是存储数据的一个容器。

为了方便我们定位容器(然后获取容器中的数据),我们通常还需要给变量 & 常量进行命名。而这个命名也不是随意起的,需要符合一定的规则(这个笔者在前面章节讲过了):

基础回顾 🚀:Java · 初窥门径 —— 标识符 & 保留字

0x02:Java · 初窥门径 —— 常量

常量通常是指代一个固定的值,可以理解为,通常不变的量

Java 中常量一般分为两类:

  • 字面常量:例如:1、2、3、’a’、’b’、true、false、”helloWorld”(部分情况可修改)。

  • 符号常量:被关键字 final 修饰的常量就是符号常量,这种值你改不了。

对于符号常量,笔者会在后续的笔记中讲解,本章我们关注的是 “字面常量”。即 ”字面意义上的常量“。以下是一些常见的字面常量:

0x0201:整型常量

整型常量是整数类型的数据, 有二进制、八进制、十进制和十六进制 4 种表示形式,具体如下:

  • 二进制:由数字 0 和 1 组成的数字序列。从 JDK 7 开始,允许使用字面值表示二进制数,前面要以 0b 或 0B 开头,目的是为了和十进制数区分,如0b011011000B10110101

  • 八进制:以 0 开头并且其后由 0~7(包括 0 和 7 )的整数组成的数字序列,如0342

  • 十进制:由数字 0~9(包括 0 和 9)的整数组成的数字序列,如198

  • 十六进制:以 0x 或者 0X 开头并且其后由 0~9、A~F(包括 0 和 9、A 和 F,字母不区分大小写)组成的数字序列,如0x25AF

0x0202:浮点数常量

浮点数常量就是在数学中用到的小数。

Java 中的浮点数分为单精度浮点数(float)和双精度浮点数(double)两种类型。其中,单精度浮点数后面以Ff结尾,而双精度浮点数则以Dd结尾。当然,在使用浮点数时也可以在结尾处不加任何后缀,此时 JVM 会默认浮点数为 double 类型,浮点数常量还可以通过指数形式表示。

浮点数常量具体示例如下:

2e3f
3.6d
0f
3.84d
5.022e+23f // 指数形式  100 => 1e2

0x0203:字符常量

字符常量用于表示一个字符,一个字符常量要用一对英文半角格式的单引号('')括起来。字符常量可以是英文字母、数字、标点符号以及由转义序列表示的特殊字符。具体示例如下:

'a'
'1'
'&'
'\r'
'\u0000'

上面示例中,'\u0000'表示一个空白字符,即在单引号之间没有任何字符。之所以能这样表示,是因为 Java 采用的是 Unicode 字符集,Unicode 字符以\u开头,空白字符在 Unicode 码表中对应的值为'\u0000'

0x0204:字符串常量

字符串常量用于表示一串连续的字符,一个字符串常量要用一对英文半角格式的双引号("")括起来,具体示例如下:

"HelloWorld"
"123"
"Welcome \n XXX"
""

一个字符串可以包含一个字符或多个字符,也可以不包含任何字符,即长度为 0。

0x0205:布尔常量

布尔常量即布尔型的值,用于区分事物的真与假。布尔常量有 true 和 false 两个值。

0x0206:null 常量

null 常量只有一个值 null,表示对象的引用为空。


其实笔者觉得这部分有点混乱,本来应该是只讲讲常量的,但是写着写着就牵扯到了 ”数据类型“。而且感觉字符常量笔者也没讲明白(读者把握核心,通常不变的量即可)。

0x03:Java · 初窥门径 —— 变量

0x0301:变量的引入

在程序运行期间,随时可能产生一些临时数据,应用程序会将这些数据保存在内存单元中,每个内存单元都用一个标识符标识,这些用于标识内存单元的标识符就称为变量,内存单元中存储的数据就是变量的值。

0x0302:变量的使用流程

其实在讲解变量的时候,还应该讲解一下变量的类型(和上面常量一样,变量也有 ”整型“、”浮点型“、”字符型“ 。。。),但是这又是一个大的知识点,笔者决定在下一章讲解。那么本章,我们先来掌握变量的使用流程(以 int 型,即整数类型举例)。

1. 变量的声明 & 赋值

要想使用一个变量,我们就得先对变量进行声明,下面是 Java 程序中声明一个变量的基本格式:

// 英文版: [ ]中的内容为可选项,即可有可无
type identifier [ = value][, identifier [= value] ...] ;
​
// 中文对照版
数据类型 变量名  [=初始值]  [,变量名  [=初始值]...];     

下面是一个 Java 变量声明与赋值(给变量赋予一个值)的示例:

public class HelloWorld {
    public static void main(String[] args) {
        // 我们可以在定义变量的同时给变量赋值
        int age = 10; // 年龄 = 10 岁, 数据类型 => int;变量名 => age;初始值 => 10; 
​
        // 我们也可以以一行定义多个变量并赋值
        int age2 = 10, width = 100, height;
​
        // 我们还可以先定义变量后赋值
        int a;
        a = 100;
​
        // 如果一个变量只是定义了,未被赋值,就等于未定义
        int b;
    }
}

上面这个示例比较 Easy,展示了各种定义变量以及赋值的方法。这里笔者再简单讲解一下关于变量声明的一个注意点:

如果你只声明一个变量,没有给变量进行赋值的话,那么其实这个变量相当于没有定义。

我们可以尝试运行上面的代码,运行后会生成一个字节码文件,下面是笔者产生的字节码文件的内容与原文件内容的对比:

另外,再提一点,Java 中不允许对一个变量进行二次定义:

2. 变量的使用

变量的使用包括对变量的重新赋值(处理),或者打印变量,看下面这个示例:

// FileName: HelloWorld.java
public class HelloWorld {
    public static void main(String[] args) {
        int age = 1;
        System.out.println("2025 今年我 " + age + " 岁了");
        age += 1; // 过了一年
        System.out.println("2026 今年我 " + age + " 岁了");
        age += 1; // 过了一年
        System.out.println("2027 今年我 " + age + " 岁了");
    }
}

0x0303:拓展 — 变量的内存分析(了解)

本小节就是一个拓展,我们从内存角度来分析变量的使用(理解底层,有助于我们后期的学习)。

1. 变量内存分析 — 加法的执行流程

先看下面这个代码,是一个简单的加法运算(其他运算都差不多):

// FileName: printMotto.java
public class printMotto {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        int c = a + b;
        System.out.print(c);
    }
}

我们以内存角度分析一下程序的运行流程:

在上图中,我们提到了一个内存地址(房间号)的概念,我们在高级语言中可以通过 ab 这样非常形象的标识符来标记变量,然而其底层逻辑,实际是 a 是一个指向某个内存的指针,你访问 a 其实就是访问 a 指向的那个内存单元格中的内容。

有点抽象是吧,没关系(以后会懂的,就是不懂也没啥关系),笔者下面来尝试借助函数打印一波内存的地址单元(你说函数咋获得?直接搜):

如上 System.identityHashCode() 可以获取变量的内存地址,我们实操一下:

// FileName: printMotto.java
public class printMotto {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        int c = a + b;
        System.out.println("变量 a 的内存地址: " + System.identityHashCode(a));
        System.out.println("变量 b 的内存地址: " + System.identityHashCode(b));
        System.out.println("变量 c 的内存地址: " + System.identityHashCode(c));
    }
}

如上,上面打印的那堆贼拉长的数,就是我们的内存房间号。

2. 变量内存分析 — 内存节省策略

这部分更是拓展中的拓展,我们在前面内存分析中写道 “住户 30 住在 c 号房”,问题来了,如果来了两个 30,那么它们在内存中是咋样的呢?是新分配一个房间还是住一起呢?

看下面的代码,我们新增了一个变量 d,且该变量的值与 c 一致,此时我们看看 dc 的内存地址:

// FileName: printMotto.java
public class printMotto {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        int c = a + b;
        int d = 30;
        System.out.println("变量 a 的内存地址: " + System.identityHashCode(a));
        System.out.println("变量 b 的内存地址: " + System.identityHashCode(b));
        System.out.println("变量 c 的内存地址: " + System.identityHashCode(c));
        System.out.println("变量 d 的内存地址: " + System.identityHashCode(d));
    }
}

如上,可以看到,值相同,打印的内存地址也一样。看来 Java 是把值一样的客人都放一起了,这样就能省开几个房间了,大大节省了我们内存空间的消耗。

0x0304:拓展 — 变量的作用域(掌握)

变量需要在它的作用范围内才可以被使用,这个作用范围被称为变量的作用域。在 Java 程序中,变量一定会被定义在一对大括号中,该大括号所包裹的代码区域便是该变量的作用域(后期会涉及更加复杂的情况,暂时读者可以先以 “{}” 作为作用域的划定)。

在讲解变量的作用域前,我们先来了解一下可以定义变量的地方,或者变量的分类:

  • 局部变量: 在一个函数(方法)或一个代码块内声明的变量。

  • 成员变量: 声明在类中,且在方法外的变量。

1. 案例演示 — 局部变量作用域

看下面这个代码,变量 A 被定义在 main() 方法中,此时我们可以在 main() 方法中输出变量 A:

public class printMotto {
    public static void main(String[] args) {
        int A = 10;
        System.out.println(A); // 这里能输出 A 的值
    }
}

main() 就是一个方法,OK,那么现在我们再创建一个 test() 方法,问,这里面能输出 A 的值吗(关于方法我们以后会讲到):

public class printMotto {
    public static void main(String[] args) {
        int A = 10;
        System.out.println(A); // 这里能输出 A 的值
    }

    public static void test() {
        System.out.print(A);
    }
}

如上,还没运行,IDE 就给我们标红了,证明那里有语法问题。其实这就是变量的作用域问题,一个大括号就是一个作用域,作用域内,我玩我的,作用域外,就不关我事了。

2. 案例演示 — 成员变量作用域

继续,看下面这个案例,我们将变量 A 声明在 printMotto 类(被 class 修饰的就是类)中,但是没有声明在任意一个方法中,问,在 main() 方法与 test() 方法中我们能调用 A 吗(static 代表静态,也是后面的内容 😂,暂时不做掌握):

public class printMotto {
    static int A = 10; // 成员变量 A
    public static void main(String[] args) {
        System.out.println(A); // 这里能输出 A 的值
    }

    public static void test() {
        System.out.print(A); // 这里也能输出 A 的值
    }
}

一样,直接看 IDE,如下,没有报错,证明是可以运行的:


原谅笔者这里真的不知道举啥例子,讲的有些抽象了,而且涉及到了很多后面才会学的知识,但是不讲又不行。对小白而言,如果看不懂也请记住这两个案例,我们在后期的编程中肯定会用到,届时有了基础的你,理解这两份代码一定会非常轻松。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Blue17 :: Hack3rX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值