Java是值传递还是引用传递一直都有争论,我们最终下个结论,Java是值传递而不是引用传递。如果Java是引用传递,我们应该可以像C语言一样交换对象,而这在Java中是做不到的。
向方法传递实例时,它的内存地址会被1比特1比特的复制到一个新的引用变量中,它们都指向相同的实例。但是如果你在方法内改变这个引用,原始引用不会改变。如果是引用传递,原始引用也会改变。
为了验证这一点,我们看下运行时的内存是如何分配的。下面的程序可以说明这个概念。
public class Foo
{
private String attribute;
public Foo (String a){
this.attribute = a;
}
public String getAttribute() {
return attribute;
}
public void setAttribute(String attribute) {
this.attribute = attribute;
}
}
public class Main
{
public static void main(String[] args){
Foo f = new Foo("f");
changeReference(f); // 这种方式不会改变引用内容
modifyReference(f); // 这种方式会改变f所指向的内容
}
public static void changeReference(Foo a) {
Foo b = new Foo("b");
a = b;
}
public static void modifyReference(Foo c) {
c.setAttribute("c");
}
}
让我们一步一步看看运行时发生了什么
1) Foo f = new Foo(“f”);
这条语句创建了Foo类的一个实例,‘attribute’被初始化为‘f’。这个实例的引用被赋给变量f
2) public static void changeReference(Foo a)
这条语句执行时,创建了一个指向Foo类型的引用 a ,初始化为 null
3) changeReference(f);
当 changeReference 被真正调用的时候,a 会指向被当做参数传进来的对象。
4) Foo b = new Foo(“b”);
和第一步一样,这条语句创建了一个Foo类的新实例,将其赋给 b
5) a = b;
这里是重点。在这,有三个变量,当语句执行的时候,a 和 b 都指向方法内部创建的同一个实例。注意:f 是没有变化的,它仍然指向原有的实例对象。没有变化!!
6) modifyReference(Foo c);
当这条语句执行的时候,创建了一个名为 c 的引用,指向 attribute 是‘f’的对象。
7) c.setAttribute(“c”);
这会改变 c 指向的对象的属性值 attribute ,而这个对象和 f 指向的是同一个对象。