参数传递机制主要有两种:值调用(call-by-value),引用调用(call-by-reference)。
值调用(call-by-value):会对实在参数求值(如果是表达式)或拷贝(如果是变量)。这些值被放在属于被调用过程的响应形式参数的内存位置上。
引用调用(call-by-reference):实在参数的地址作为相应的形式参数的值被传递给被调用者。在被调用者的代码中使用形式参数时,实现方法是沿着这个指针找到调用者指明的内存位置。因此,改变形式参数就像改变了实在参数一样。C++就是用的引用调用。
看上去JAVA的调用也仿佛是引用调用,而直到最近,我才弄明白,原来JAVA是值调用的。也就是说,当JAVA程序里的实在参数是变量时(非表达式),函数会为实在参数复制一个变量给形式参数,该变量的指针与实在参数的指针一样,都指向了实在参数所对应的内存地址,即对象。而在函数内部修改形式参数所对应的对象的值的时候,其实就是修改了实在参数所指向的那个对象,也就是说他们指向同一个对象。但,假如在函数内部改变了对形式参数的引用,比如将形式参数的引用指向了另一个对象,此时函数对形式参数所指对象的修改就变成了对新对象的修改,而实际参数所指向的对象并没有改变。简单点说,就是:无论是否在函数内将形式参数的引用改变,实际参数的引用都不会改变。
JAVA编译器通过对变量引用的方式,实现了引用调用的功能,用的却是值调用,以至于当变量被传递给函数调用后,不论什么情况,该变量所指的对象不会变。
下面的程序简单地证明了以上的调用机制。
private static int[] argumentTest(int[] input){
System.out.println("here come the input's items :");
for (int i : input)
System.out.print(i + " ");
System.out.println();
input = new int[]{1,2,3};
System.out.println("the input's reference has been changed here, you can see the current input's items :");
for (int i : input)
System.out.print(i + " ");
System.out.println();
return input;
}
public static void main(String[] args) {
int[] input = new int[]{3,2,1};
int[] output = argumentTest(input);
System.out.println("the input's reference has been changed in function argumentTest,but out of the function, the input remains the same as the one before invoked by argumentTest :");