本文是读 李刚 编写的 《疯狂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 的值是: 101.当程序进入到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)同时执行了堆内存中的一个对象;所以操作任何一个引用变量都会影响到在堆内存中的实际对象的值;