在开始之前先来看看下面这段代码:
public class Test {
private String props;
public String getProps() {
return props;
}
public void setProps(String props) {
this.props = props;
}
public void method(Test test) {
test.setProps("b");
System.out.println(test.getProps());
test = new Test(); //***请注意这里***
test.setProps("c");
System.out.println(test.getProps());
}
public static void main(String[] args) {
Test ts = new Test();
ts.setProps("a");
// Test ts = new Test();
ts.method(ts);
System.out.println(ts.getProps());
}
}
看完这段代码我相信很多人都有了自己的答案。那么在讨论之前,说明按值传递和按引用传递这两个术语是重要的。按值传递意味着当将一个参数传递给一个函数时,函数接收的是原始值的一个副本。因此,如果函数修改了该参数,则仅改变副本,而原始值保持不变;按引用传递意味着当将一个参数传递给一个函数时,函数接收的是原始值的内存地址,而不是值的副本。因此,如果函数修改了该参数,调用代码中的原始值也随之改变。 Java 中的变量可以分为以下两种类型之一:基本类型和引用类型。说到这我想你应该更加坚信自己的答案了(对的或错的),也或者是对这个问题嗤之以鼻。
如果你的答案是:b c c,那你要么是受C++影响太深,要么是被市面上那些滥竽充数的教材所毒害。实际上,这段代码的运行结果是:b c b(当然它们之间有换行)。若这跟你心中的答案是一样的,那么我建议你关掉此网页,去别处逛逛吧,它不适合你。
Java 语言有基本类型和对象引用类型,因此认为 Java 对基本类型使用按值传递,而对引用使用按引用传递是符合逻辑的。很容易就会相信这一点,实际上有很长一段时间我也认为是这样,但这不正确。
在 Java 中,当对象引用是传递给方法的一个参数时,你传递的是该引用的一个副本(按值传递),而不是引用本身。请注意,传给方法的副本跟对象引用都指向同一个对象。Java 在参数传递中,处理基本类型和引用类型的方式是相同的。两种类型都是按值传递的;没有一种按引用传递。这是一个重要特性,正如上面的代码运行结果所表现的那样。也就是说,Java 按值传递所有参数,即制作所有参数的副本,而不管它们的类型。
我必须承认,我曾一直认为因为 Java 有两种类型,所以他们按值传递基本类型而按引用传递引用类型,就像 C++ 那样。但是,当我理解了发生的事情,我就开始相信 Java 按值传递所有参数的方法更加直观。The Java Programming Language,Second Edition 的作者,Ken Arnold 和 James Gosling 在 2.6.1 节中说得好:“在 Java 中只有一种参数传递模式 - 按值传递 --- 这有助于使事情保持简单。”