本文最后更新于 1034 天前,其中的信息可能已经有所发展或是发生改变。
首先明确一点,就是 ==
运算符的作用就是比较两边变量所指向内存地址是否相同。
基本类型的赋值与内存地址
首先来看这个例子:
int i1 = 123;
int i2 = 123;
int i3 = i1;
System.out.println(i1 == i2); // true
System.out.println(i1 == i3); // true
i3 = 321;
System.out.println(i1 == i3); // true
可以得出几个结论:
- 对于基本类型,值相等的变量,它们指向的内存地址也是相同的;
- 对于基本类型,将一个变量赋予另一变量,两者指向的内存地址也是相同的;
- 对于基本变量,如果两个变量先前指向的内存地址是相同的,但是后来有一个变量修改了值,那么修改值后两个变量的内存地址就不再相同。
总结一下,就是值相同,地址就相同。
数组类型的赋值与内存地址
来看 Java 数组的例子:
int[] array1 = {1, 2, 3};
int[] array2 = {1, 2, 3};
int[] array3 = array1;
int[] array4 = new int[] {1, 2, 3};
System.out.println(array1 == array2); // false
System.out.println(array1 == array3); // true
System.out.println(array1 == array4); // false
array3[0] = 10;
System.out.println(array1 == array3); // true
// array1 = {10, 2, 3}
// array3 = {10, 2, 3}
可以得出几个结论:
- 对于数组类型,两个数组变量哪怕内容相同,它们指向的地址也是不同的;
- 对于数组类型,一旦将一个变量赋值给另一个变量,那么这两个数组变量都将指向同一个内存中的数组数据。修改一个变量,另一个变量也会随之修改;
- 对于数组类型,不管用不用
new
,都会创建一个新的数组。
总结来说,只有将一个变量赋值给另一个变量,两者地址才相同。
对象类型的赋值与内存地址
来看这样的例子:
var t1 = new TodolistItem("Todolist title");
var t2 = new TodolistItem("Todolist title");
var t3 = t1;
System.out.println(t1 == t2); // false
System.out.println(t1 == t3); // true
t3.setTodolistTitle("new title");
System.out.println(t1.getTitle()); // "new title"
System.out.println(t3.getTitle()); // "new title"
TodolistItem
是一个 JavaBean 类,根据上面的例子可知:
- 对于对象类型,不管对象内的字段是否相同,它们指向的地址也是不同的;
- 对于对象类型,一旦将一个变量赋值给另一个变量,那么这两个对象变量都将指向同一个内存中的对象数据。修改一个变量,另一个变量也会随之修改。
和数组类型差不多,只有将一个变量赋值给另一个变量,两者地址才相同。
String 类型的赋值与内存地址
String 类型对象有两种创建方式:
String s1 = "String Content";
String s2 = new String("String Content");
这两种创建 String 对象的方式要分开来进行分析。
直接创建字符串方式
首先是直接创建字符串的方式:
String s1 = "String Content";
String s2 = "String Content";
String s3 = s1;
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // true
s3 = "new Content";
System.out.println(s1); // "String Content"
System.out.println(s3); // "new Content"
System.out.println(s1 == s3); // false
根据上面的例子可知:
- 直接定义的字符串,如果字符串内容相同,则地址相同;
- 将直接定义的字符串变量直接赋值给另一个变量,那么两个变量指向的地址是相同的;
- 如果两个指向相同内存地址的变量中的一个字符串变量发生变化,另一个变量不会随之变化,两者指向的地址也不再相同。
简单来说,就是和基本类型的情况差不多。
通过 new 创建字符串方式
另一种是通过 new
来创建的字符串:
String s1 = new String("String Content");
String s2 = new String("String Content");
String s3 = s1;
System.out.println(s1 == s2); // false
System.out.println(s1 == s3); // true
s3 = "new Content";
System.out.println(s1); // "String Content"
System.out.println(s3); // "new Content"
System.out.println(s1 == s3); // false
根据上面的例子可知:
new
创建的字符串,即便内容相同,地址也不相同;- 如果将
new
创建的字符串变量直接赋值给另一个变量,那么两个变量指向的地址是相同的; - 如果两个指向相同内存地址的变量中的一个字符串变量发生变化,另一个变量不会随之发生变化,两者指向的地址也不再相同。
顺便说一句,例子中用的是 s3 = "new Content";
,用 s3 = new String("new Content");
效果也是一样的。
String 类型的赋值总结
可以看到,String 类型虽然也是对象类型,但是和其他对象类型还是不太一样的。
String 类型有两种创建的方式,其中直接用双引号来创建字符串对象的方式和基本类型没什么区别;但另一种通过 new
创建字符串对象的方式,它和基本类型或者对象类型都是不相同的。所以 String 类型的赋值与地址之间的关系要单独理解记忆。
总结
总结得到下表所示的规律:
类型 | 值相同时地址是否相同 | a==b 时修改 a ,此时 b 是否会发生变化 |
---|---|---|
基本类型 | 相同 | 不会改变,一旦 a 发生变化,a 和 b 的地址就不再相同 |
数组类型 | 不相同 | 会发生改变,a 和 b 的地址始终是相同的 |
对象类型 | 不相同 | 会发生改变,a 和 b 的地址始终是相同的 |
直接定义的字符串对象 | 相同 | 不会改变,一旦 a 发生变化,a 和 b 的地址就不再相同 |
new 创建的字符串对象 | 不相同 | 不会改变,一旦 a 发生变化,a 和 b 的地址就不再相同 |