Java 中的对象引用,一般出现在赋值与方法传递场景,下面分别予以说明。
1 赋值
赋值使用的是符号 =
,表示获取 =
右边的值赋给左边的变量。右边可以是任何常量、变量或者可产生一个返回值的表达式,但左边必须是一个明确的、已命名的变量。也就是说,可以是 x = 3,但不可以是 3 = x。
如果右边是基本类型,那么会直接赋值。比如 x = y,如果 y 是基本类型,那么赋值操作会将 y 的值复制一份给变量 x。
但如果是对象赋值,实际上是将右边的对象的引用赋给左边的对象。请看下例:
class Cup {
String color;
}
public class Assignment {
public static void main(String[] args) {
Cup cup1 = new Cup();
Cup cup2 = new Cup();
cup1.color = "red";
cup2.color = "yellow";
System.out.println("1: cup1.color:" + cup1.color + ", cup2.color:" + cup2.color);
cup1 = cup2;
System.out.println("2: cup1.color:" + cup1.color + ", cup2.color:" + cup2.color);
cup1.color = "black";
System.out.println("3: cup1.color:" + cup1.color + ", cup2.color:" + cup2.color);
}
}
运行结果:
1: cup1.color:red, cup2.color:yellow
2: cup1.color:yellow, cup2.color:yellow
3: cup1.color:black, cup2.color:black
在 Java 中,由于赋予的是对象引用,所以执行 cup1 = cup2;
之后,cup1 与 cup2 实际上指向的是同一个引用,之后改变 cup1 的属性值,也就改变了 cup2,因为 cup1 和 cup2 此时指向的是堆中同一个对象。而 cup1 的原始对象引用在执行 cup1 = cup2;
之后便将其丢弃,这个引用对象会在垃圾回收时被清理。
这种情况,在英文中叫做 aliasing,原意是别名,也就是说,执行 cup1 = cup2;
之后,cup1 其实是 cup2 的别名。
2 方法传递
把对象传递给方法时,也会发生 aliasing。
public class ObjectToMethod {
static void color(Saucer s) {
s.color = "red";
}
public static void main(String[] args) {
Saucer saucer = new Saucer();
saucer.color = "blue";
System.out.println("1: saucer.color:" + saucer.color);
color(saucer);
System.out.println("2: saucer.color:" + saucer.color);
}
}
运行结果:
1: saucer.color:blue
2: saucer.color:red
这里,我们给方法 color() 传递了一个引用,这个方法在内部改变了这个引用所对应的对象属性值,实际上影响到了外层的这个对象。
因为引用传递给方法时,这个引用仍然指向的是同一个对象。
public class ReferencesToMethod {
public static void m(ReferencesToMethod r) {
System.out.println("m() 中的对象:" + r);
}
public static void main(String[] args) {
ReferencesToMethod r = new ReferencesToMethod();
System.out.println("main() 中的对象:" + r);
m(r);
}
}
运行结果:
System.out.println() 中的 r 变量,会直接调用 toString() 方法,它默认打印的是对象的类与对象所在地址,可以看到两个地址一模一样,从而证明了是同一个对象。