本文是读 李刚 编写的 《疯狂Java讲义》中的5.2.2节的读书笔记的整理;
Java里的参数传递类似于《西游记》里的孙悟空,孙悟空复制一个假的孙悟空,这个假孙悟空具有和真孙悟空相同的能力,可除妖或被砍头,但不管这个假孙悟空遇到什么事,真孙悟空不会受到任何影响。与此类似,传入方法的是实际参数值得复制品,不管方法中对这个复制品如何操作,实际参数值本身不会受到任何影响
---李刚
无论是基本类型的参数传递还是引用类型的参数传递;本质都是值传递,在引用类型的参数传递时,容易给人造成困惑的主要原因是,我们要分清,在创建一个对象是,引用变量保持在栈内存中,在堆内存中保存的是真是创建出来的对象,并且栈内存中保存了对象在堆内存中的首地址,那么在参数传递时实际是传递的栈内存中的对象首地址,这样就会造成方法中的形参也会指向堆内存中的实际对象,因此在方法中对对象的修改会影响到实际堆内存中的对象;
1. 基本类型的参数传递问题图解:
public class NewObjectTest {
public static void swap(int a,int b){
int tmp = a;
a = b;
b = tmp;
System.out.print("swap 方法中,a 的值是: "+a+"; b 的值是: "+b);
}
public static void main(String[] args) {
int a=5, b=10;
swap(a,b);
System.out.print("交换结束后,a 的值是: "+a+" b 的值是: "+b);
}
}
输出结果为:
swap 方法中,a 的值是: 10; b 的值是: 5
交换结束后,a 的值是: 5 b 的值是: 10
1.当程序进入到main方法中,会在main栈区保持main()方法中的局部变量 a 和 b (a=5,b=10) ;
2.在main方法中调用 swap(a,b)方法,此时开辟一个swap的栈区来保持形参 a 和 b;并将main()方法栈中a和b变量的值分别赋给swap方法栈中的a和b参数,也就是对 swap方法的a 和b 的形参进行了初始化; 此时系统中存在着 两个a变量和两个b变量,只是存在了不同的方法栈区中;
3.程序在swap中交换 a 和 b 的变量值,此时在swap方法栈中 tmp=5, b=5, a=10; 也就是说swap方法只是交换了swap方法栈区中的变量,并没有交换main栈区中的变量a和b的值;
所以可以清楚的看出,在基本类型的数据是值传递;
2.引用类型的参数传递
class DataWrap{
private int a;
private int b;
public DataWrap(int a,int b){
this.a = a;
this.b = b;
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
@Override
public String toString() {
return "DataWrap [a=" + a + ", b=" + b + "]";
}
}
public class ReferSwapTest {
public static void swap(DataWrap dataWrap){
int tmp = dataWrap.getA();
dataWrap.setA(dataWrap.getB());
dataWrap.setB(tmp);
System.out.print("swap方法中:"+dataWrap.toString());
}
public static void main(String[] args) {
DataWrap dw = new DataWrap(10,20);
swap(dw);
System.out.print("swap方法结束后 :"+dw.toString());
}
}
输出结果为:
swap方法中:DataWrap [a=20, b=10]
swap方法结束后 :DataWrap [a=20, b=10]
给人的错觉:swap中 a 和 b 的值发生了交换,不仅如此,当swap方法执行结束后,main方法中的a和 b的值也发生了改变,这和基本数据类型给人的感觉不同;
原因分析:
1.当程序执行到main方法中的 DataWrap dw = new DataWrap(10,20);时,main方法创建了一个DataWarp对象,并定义了一个dw引用变量来指向DataWarp对象;此时和基本类型有很多的区别;创建一个对象时,系统内存中有两个东西,堆内存中存储了对象本身(a=10,b=20),main栈区内存中保存了引用该对象的引用变量(dw=Ox14ff12);
2.当调用swap(dw); JVM会开辟一个swap方法栈区,并创建引用变量dataWarp,并且会吧dw的值(DataWarp对象在堆内存中的首地址)赋给swap方法栈区中的变量dataWarp, (dataWarp=dw=Ox14ff12); 此时注意:有两个引用变量(main栈区中的引用变量dw, swap栈区中的引用变量dataWarp)同时执行了堆内存中的一个对象;所以操作任何一个引用变量都会影响到在堆内存中的实际对象的值;