Java方法的参数传递机制详解

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



猜你喜欢

转载自blog.csdn.net/managementandjava/article/details/79002077