我们都知道,“=”等号操作符在编码语言中是个神奇的符号,因为它表示赋值操作而不是单纯的“等于”。我们也知道,“=”进行赋值操作时,有左值和右值的说法,当然左值和右值这里就不详述了,这个不是本文的重点。那么,下面,简单对java中的“=”操作符进行一下简单的说明:
首先,java中的数据类型分为两大类,基本类型和引用类型,基本类型:int、byte、char、short、long、float、double、boolean。引用类型:String、Array、Object。
那么先比较下面两段代码:
1.
1 int a = 3; 2 int b = a; 3 b++; 4 System.out.println(a);
2.
1 String a = "Hello"; 2 String b = a; 3 b = b + "World"; 4 System.out.println(a);
最终的结果将是上面的
a = 3;
a = "Hello"; 表面上看
a的值都没有改变但实际上两者的机制是不一样的。
对基本类型进行“=”只是一个赋值操作,就是将
a这个变量进栈,并将
a的内存区域的内容设成
3。
而引用类型进行“=”却是引用操作,说具体一些就是地址的传递,开始我们
String a = "Hello";时,实际上是堆中开辟了一块内存,内存中存放的内容是字符串
"Hello"对象, 而变量
a却是我们在栈中声明的,这个“=”操作符是让
a去引用
"Hello"这个对象,
a真正的值应该是
"Hello"字符串对象的地址!而
String b = a; 时;这时候是将
a的地址赋值给了
b(引用是地址的赋值),
a、
b的值都是同一个地址,那么
a、
b指向的是同一个对象,
b = b + "world";
实际上改变了b所引用的对象,不是b所引用的对象的值。
b重新引用了另外一个对象
"Helloworld",
a还是引用
"Hello"这个字符串对象。当然
System.out.println(a)的值不会改变(这个,笔者暂时理解成为
println方法传递引用类型对基本类型的一个重载,感兴趣的可以查阅一下javadoc,这个还有待验证)。
拓展一下,讲一下java的内存回收机制,以下面的一段代码为例:
1 String a = "Hello"; 2 a = a + "World"; 3 System.out.println(a);
看一下
a = a + "World";这句,我们前面已经知道了
a是对堆中某块内存对象的引用,
a + "World";给我们的第一反应就是将这块内存中的改为
"HelloWorld",实际则不然,"Hello"这个String类型的对象在初始化后就已经是不可变的了,
a = a + "World";实际上是在堆区另外开辟一块内存,内存中的内容是"HelloWorld",原来存放"Hello"的那块内存区域会被回收,a重新引用"HelloWorld"这块内存区域,a的值(a的地址)也会改变。
再看一个例子:
1 public class Text{ 2 private String word; 3 public void setWord(String Word){ 4 this.word = Word; 5 } 6 public void printWord(){ 7 System.out.println(this.word); 8 } 9 } 10 public class Main{ 11 public static void main(String[] args){ 12 Text t1 = new Text(); 13 t1.setWord("Hello"); 14 Text t2 = t1; 15 t2.setWord("HelloWorld"); 16 t1.printWord(); 17 } 18 }
t1.printWord()输出的却是"HelloWorld";说明在Text t2 = t1;时,t2引用了t1所引用的对象,就是new Text()初始化的对象,
t2.setWord("HelloWorld");时,这个对象的成员word被改变了,就是说t2.word引用的对象的地址变了,但是t1、t2引用的由new Text();初始化的这个对象却没有改变,因为t1还引用原来的对象,t1.word也会改变。
最后用一句话总结:变量可以引用对象,但是变量不是对象!