java,call-by-value还是call-by-reference?
我们都知道,在java语言中,对于几种基本数据类型,都是call-by-value,如以下例子:
public static void tripleValue(double x) // doesn't work
{
x = 3 * x;
}
public static void main(Strings[] args)
{
double percent = 10;
tripleValue(percent);
}
这个例子中,并没有实现将percent乘三,因为基本数据类型是call-by-value。
但是对于引用类型呢?是call-by-value还是call-by-reference呢?先看一个例子:
class Employee { ... private double salary; public void raiseSalary(double byPercent) { double raise = salary * byPercent / 100; salary += raise; } } class test { public static void main(String[] args) { harry = new Employee(); tripleSalary(harry); } public static void tripleSalary(Employee x) // works { x.raiseSalary(200); } }
这个例子中,能够成功地把harry的薪水上涨两倍,为什么呢?看一下过程:
首先,tripleSalary(harry)先复制harry给x。harry是什么?是一个Employee引用,所以得到x也是一个Employee也是一个引用,且这两个引用指向同一个对象,然后tripleSalary方法中,x再调用raiseSalary方法,因为x是一个对象的引用,所以此时确实改变了所指对象的salary域,所以方法调用结束后,harry的salary发生了改变。整个过程通过下图一目了然:
那么,对于引用对象,方法参数传递的是地址吗?
其实不是,再通过最后一个例子就可以看清楚了:
class test { public static void swap(Employee x, Employee y) // doesn't work { Employee temp = x; x = y; y = temp; } public static void main(String[] args) { Employee a = new Employee("Alice", . . .); Employee b = new Employee("Bob", . . .); swap(a, b); // does a now refer to Bob, b to Alice? } }
这个例子最后并没有真正交换a和b所引用的对象,为什么呢?看下图就可以知道:
可以看出,在调用swap(a, b);时,a、b各复制一个副本给x、y,然后交换x、y所引用的对象,最后退出函数调用时,x、y销毁,但是a、b所引用的还是原来的对象,并没有实现交换的目的,因此,对于引用对象类型,方法参数传递仍是call-by-value,只是第二个例子中,复制的是对象的引用,并且在方法内使用这个引用改变了对象的状态,最后让我们看到的好像是call-by-reference的假象,但其实还是call-by-value,只是这时的value是一个reference,第三个例子也一样,只不过第三个例子中没有通过这个引用在方法内修改这个对象而已,所以方法调用结束后,复制的value自动销毁。