简述
调用方法的时候,有需要传参数的情况。在Java中,参数的类型有基本类型和引用类型两种。
一开始听到一个说法,Java没有引用传递,但是一直没有太多的思考在上面,直到前不久玩数组的时候,突然间发现把数组引用变量作为参数传递到一个方法当中进行操作之后,再去访问原数组,原数组元素的值竟然改变了。于是乎,就想到了之前在C++里面学过的引用传递,突然有一种错愕的感觉,就查了一些资料,探究当Java将引用类型变量作为参数传递给方法的时候,到底是值传递还是引用传递。
结论:如果将Java引用类型变量作为参数传递给方法,是将引用变量的值传递给形参,而引用变量的值实际上就是引用对象在堆内存中的地址。也就是说,这个时候实参和形参指向了同一个对象,如果利用形参进行操作,操作的就是实参指向的对象,最后通过实参的那个引用访问,自然是被形参操作过的结果。
基本类型参数
基本类型参数是典型的值传递,著名的案例就是更换两个数的值。下面是这个问题的示例代码:
public class Main {
public static void main(String[] args) {
int num1 = 11;
int num2 = 22;
System.out.println("Before the call: num1 is " + num1 + " and num2 is " + num2);
swap(num1, num2);
System.out.println("After the call: num1 is " + num1 + " and num2 is " + num2);
}
public static void swap(int num1, int num2) {
System.out.println("num1 is " + num1 + " and num2 is " + num2 + " in method of swap.(before)");
int tmp = num1;
num1 = num2;
num2 = tmp;
System.out.println("num1 is " + num1 + " and num2 is " + num2 + " in method of swap.(after)");
}
}
运行结果如下:
Before the call: num1 is 11 and num2 is 22
num1 is 11 and num2 is 22 in method of swap.(before)
num1 is 22 and num2 is 11 in method of swap.(after)
After the call: num1 is 11 and num2 is 22
通过运行结果,可以清楚地知道,通过这样的参数传递,交换的仅仅是形参的值,而main方法当中的两个数的值并没有发生变化。这就是值传递的结果。(具体如何通过方法交换基本类型的变量的值,可以参看笔者的另一篇博客:如何通过方法实现基本类型的数值交换。)
引用类型参数
通过一个数组引用演示引用类型参数的传递效果
public class ArrayTest {
public static void main(String[] args) {
int[] arr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
System.out.print("Before calling the inversion: ");
for (int i : arr) {
System.out.printf("%3d", i);
}
System.out.println();
inversion(arr);
System.out.print(" After calling the inversion: ");
for (int i : arr) {
System.out.printf("%3d", i);
}
System.out.println();
setNull(arr);
System.out.println("@" + arr);
}
public static void inversion(int[] arr) {
int length = arr.length;
for (int i = 0; i <= length / 2; i++) {
int temp = arr[i];
arr[i] = arr[length - i - 1];
arr[length - i -1] = temp;
}
}
public static void setNull(int[] array) {
System.out.println("#" + array);
array = null;
System.out.println("$" + array);
}
}
程序运行结果:
Before calling the inversion: 0 1 2 3 4 5 6 7 8 9
After calling the inversion: 9 8 7 6 4 5 3 2 1 0
#[I@1d251891
$null
@[I@1d251891
程序中,在main方法中定义了一个数组,并且在类中定义了一个将数组元素倒置的方法inversion(),这个方法需要传入一个数组类型的引用。在main方法中调用这个方法,并将arr这个数组的引用作为参数传递给inversion方法,通过程序执行的结果,可以看到当inversion方法执行完毕,main方法中的arr数组的内容的确发生了倒置。
那么,这个时候是否就可以认为,引用类型的传递是引用传递而并非值传递呢?按照资料显示的,引用类型的参数传递传递的是引用变量的值,有什么方法可以证明一下呢?setNull()方法提供了这样的证明。
setNull方法的参数是数组的引用变量,程序中传入的是arr.进入方法,首先打印了array,然后将它置空再打印一次,然后在main方法中,打印arr的地址。程序运行的结果表示,array置空之前和arr指向的是同一区域,而后array=null却并没有影响到arr.
所以,可以肯定,当一个引用类型的变量被作为参数传递到方法中的时候,仅仅是将变量值复制后传递过去,而本身没有发生改变去指向其他。
当array=null的时候,array指向堆区的引用失效了。
以上的示例和分析都表明,Java中的确没有引用传递,当把一个引用类型的变量作为参数传递给方法的时候,也仅仅是将引用变量的值复制一份给了方法中的参数,自己始终指向原本的对象。