Java方法的参数传递方式只有一种:值传递,即将实参的副本传递给方法,参数本身不发生任何变化。先看看基本类型参数的传递示例:
public class TestPassPrimitiveArgs {
public static void swap(int a, int b) {
System.out.println("交换前,a = " + a + ", b = " + b);//a = 3,b = 5
int temp = a;
a = b;
b = temp;
System.out.println("交换后,a = " + a + ", b = " + b);//a = 5,b = 3
}
public static void main(String[] args) {
int a = 3;
int b = 5;
swap(a, b);
System.out.println("交换结束后,a = " + a + ", b = " + b);//a = 3,b = 5
}
}
从运行结果来看,在swap()中交换之前是3和5,交换后变成5和3,而实参在main()中始终变成不变,因此在main()传递给swap()的实参只是a和b的副本,而不是a和b本身。我们以内存分布来说明执行状况,当在main()中传参给swap()时,实际上就是在main()方法栈区向swap()方法栈区传递一份a和b的副本,如下图:
当执行swap()时,swap()方法栈区将a和b副本进行交换,交换完成后进入main()方法栈区,此时仅仅a和b的副本发生改变,其本身没有发生任何变化。接下来我们来看看引用类型的交换,前面我们说了只能通过值传递的方式来传参,可能对有些朋友来说稍显疑惑。
class DataSwap {
public int a;
public int b;
}
public class TestPassReferenceArgs {
public static void swap(DataSwap ds) {
System.out.println("交换前,ds.a = " + ds.a + ", ds.b = " + ds.b);//ds.a = 3, ds.b = 5
int temp = ds.a;
ds.a = ds.b;
ds.b = temp;
System.out.println("交换后,ds.a = " + ds.a + ", ds.b = " + ds.b);//ds.a = 5, ds.b = 3
}
public static void main(String[] args) {
DataSwap ds = new DataSwap();
ds.a = 3;
ds.b = 5;
swap(ds);
System.out.println("交换结束后,ds.a = " + ds.a + ", ds.b = " + ds.b);//ds.a = 5, ds.b = 3
}
}
从运行结果来看,确实不仅在swap中交换成功,在main中仍然是交换之后的结果。让人一下觉得:从main中传递给swap似乎不是ds对象的副本了,而是ds本身,这与我们前面谈到的Java方法传参只能按值传递相违背了,下面我详细说明一下。我们都知道,此时传递的是引用类型DataSwap,而引用类型的内存方式已经谈过了,在main()方法栈区中实际存放的是ds对象的地址,而实际的数据(a,b)是存放在堆内存中。现在将ds对象引用由main传递给swap,实际上是ds对象的地址复制一份到swap方法栈区中,此时main和swap中都已拥有ds对象的地址,且都指向在堆内存中实际存放的数据。也就是说引用类型参数数据传递方式是不折不扣的值传递方式,只不过传递的仅仅是引用变量,而不是引用变量所指向的引用类型数据。当然这里对main或swap中任何一个ds对象数据的更改都会影响到另一方,同时我们还可以验证main和swap中的ds是两个不同的引用变量,试着在swap种方法最后添加: ds=null.也就是切断swap中对ds的引用,查看一下main中ds对象的a和b是否受到影响(结果是不会)。