我在看《Java编程思想》一书时,看到操作符章节下面的:方法调用中的别名问题,于是就有了这篇文章。
我先总结出核心观点:这个小章节,方法调用中的别名问题,其实就是讨论 Java 中方法传递的到底是值还是引用。
Java 中方法只有值传递
赋值
赋值操作符使用「=」:取取右边的值把它复制给左边。这个当然简单,就不过多解释了。以下用代码解释,都是完整可运行的代码。
-
值赋值
public class TestObject { public static void main(String[] args) { int a = 1; int b = 2; System.out.println("a=" + a + "," + "b=" + b); a = b; System.out.println("a=" + a + "," + "b=" + b); a = 3; System.out.println("a=" + a + "," + "b=" + b); } } //outPut: a=1,b=2 a=2,b=2 a=3,b=2
a = b,只是把 b「值」赋给了 a ,所以当 a 改变时,并不影响 b 的值。
-
对象赋值
class Thak {
int level;
}
public class TestObject {
public static void main(String[] args) {
Thak t1 = new Thak();
Thak t2 = new Thak();
t1.level = 1;
t2.level = 2;
System.out.println("t1.level=" + t1.level + "," + "t1.level=" + t2.level);
t1 = t2;
System.out.println("t1.level=" + t1.level + "," + "t1.level=" + t2.level);
t1.level = 3;
System.out.println("t1.level=" + t1.level + "," + "t1.level=" + t2.level);
}
}
//outPut:
t1.level=1,t1.level=2
t1.level=2,t1.level=2
t1.level=3,t1.level=3
此时,赋值操作的是一个对象的引用,所以修改了 t1,也同时改变了 t2。
原本 t1 包含的对对象的引用,是指向一个值为 1 的对象。在对 t1 赋值时,这个引用被覆盖。原本 t1 包含的对对象的引用,是指向一个值为 1 的对象。在对 t1 赋值时,这个引用被覆盖,也就是丢失了;而那个不再被引用的对象会由“GC”自动清理。
Java 中这种特殊现象叫 “别名现象”,是 Java 操作对象的一种基本方式。
在上面这个问题中,我们如何避免这个 “别名现象” 呢?
t1.level = t2.level; //即可
方法调用中的别名
我在看了这个小章节后,Java 方法调用中的别名问题,其实就是讨论 Java 中方法传递的到底是值还是引用。
class Letter {
char c;
}
public class TestObject {
static void f(Letter y){
y.c='b';
}
public static void main(String[] args) {
Letter x = new Letter();
x.c='a';
System.out.println("main:"+x.c);
f(x);
System.out.println("f:"+x.c);
}
}
//outPut:
main:a
f:b
你上面不是说,Java 中只有「值传递」吗,为什么 c 的值会改变。
是的,Java 值只有值传递,只不过这里值的内容是引用。
Java 中只有值传递
这个问题,我就不再赘述了,已经有好多好文章非常详细的阐述了这个问题。下面我给出连接,大家自行去看:
Hollis-为什么 Java 只有值传递 :这个是我非常喜欢的一个博主,你去看他的这边文章,非常仔细的阐述了为什么 Java 中只有值传递,我觉得我再写一遍,就是多此一举了。
Stack Overflow :这个当然是有着超高人气的网站啊,关于 Is Java “pass-by-reference” or “pass-by-value”? 的讨论也是非常火热。
关于文章嘛,我觉得主要是解决自己的疑惑,而不在于是不是自己亲手写的,我觉得上面两篇文章,都已经有很好或者完美的解释了,我再写下去也没必要,倒不如,放出链接,给正在看的你。