On Java:中文版·基础卷
上QQ阅读APP看书,第一时间看更新

4.3 赋值

操作符=用来赋值。它的意思是“取等号右边的值(一般称作右值),把它复制给等号左边(一般称作左值)”。右值可以是任何常量、变量或者可以产生值的表达式。但左值必须是一个独特的命名变量(也就是说,必须有一个物理空间来存储右值)。比如,你可将一个常量赋值给一个变量:

但不能把任何东西赋值给一个常量,常量不能作为左值(不能说4=a;)。

基本类型的赋值是很直观的。基本类型存储了实际的值,而非指向一个对象的引用,所以在为其赋值的时候,你直接将一个地方的内容复制到了另一个地方。例如,对基本数据类型而言,a=b就是将b的内容复制给a。如果你接着修改了a,b并不会受这个修改的影响,大多数情况下这也是我们所期望的。

不过在给对象赋值的时候,情况发生了变化。当操作一个对象的时候,我们真正操作的是这个对象的引用。所以当“将一个对象赋值给另一个对象”时,你其实是将这个引用从一个地方复制到另一个地方。这意味着对对象而言,c=d就是将c和d都指向原本只有d指向的那个对象。下面这个示例将演示这种行为:

Tank类非常简单,它的两个实例(t1和t2)是在main()方法里生成的。每个Tank类对象的level字段都被赋了一个不同的值,然后t2被赋给t1,接着又修改了t1。在许多编程语言里,你可能会认为t1和t2总是相互独立的。但由于赋值操作的是引用,修改t1的同时显然也改变了t2!这是因为t1和t2包含了指向相同对象的引用(t1最初包含的引用指向了那个字段值为9的对象,当对t1重新赋值的时候,这个引用被覆盖了,因此对象丢失了,它对应的对象也会由垃圾收集器清理)。

这种现象通常称作“别名”,是Java操作对象的一种基本方式。不过,如果你不想让别名出现在这里,应该怎么办呢?可以不按之前的赋值处理,而像下面这样写:

这样就可以保持两个对象彼此独立,而不是丢弃一个对象,然后将t1和t2都绑定到剩下的那个对象上。直接操作对象内部的字段违背了Java的设计原则。这不是一个小问题,所以你需要时刻注意,为对象赋值可能会产生意想不到的结果。