实参:如果声明方法时包含来了形参声明,则调用方法时必须给这些形参指定参数值,调用方法时传给形参的参数值也被称为实参。
Java的实参值是如何传入方法?这是由Java方法的参数传递机制来控制的,Java里方法的参数传递方式只有一种:值传递。所谓值传递,就是将实际参数的副本(复制品)传入方法内,而参数本身不会收到任何影响。
下面通过一个程序来演练 参数类型是原始类型的值传递的效果:
public class ParamTransferTest { public static void swap(int a,int b){ //下面三行代码实现a、b变量的值交换 //定义一个临时变量来保存a变量的值 int temp=a; //把b的值赋给a a=b; //把临时变量temp的值赋给a b=temp; System.out.println("swap方法中,a的值是:"+a+", b的值是:"+b); } public static void main(String[] args) { int a=6; int b=9; swap(a, b); System.out.println("交换结束后,变量a的值是:"+a+", 变量b的值是:"+b); } }
程序结果为:
swap方法中,a的值是:9, b的值是:6 交换结束后,变量a的值是:6, 变量b的值是:9
从上面运行结果来看,swap方法中的a和b的值是9、6,交换结束后,变量a和b的值依然是6、9。
从这个运行结果可以看出,main方法里的变量a和b,并不是swap方法中的a和b。
swap方法中的a和b只是main方法中的变量a和b的复制品。下面通过示意图来说明上面程序的执行过程。
Java程序总是从main方法开始执行,main方法开始定义了a、b两个局部变量,两个变量在内存中存储示意图如图1所示。
当程序执行swap方法是,系统进入swap方法,并将main方法中的a、b变量作为参数传入swap方法,传入swap方法的只是a、b的副本,而不是a、b本身,进入swap方法后系统产生了4个变量,这4个变量在内存中的存储示意图如图2所示。
在main方法中调用swap方法时,main方法还未结束。因此,系统分别为main方法和swap方法分配两块栈区,用于保存main方法和swap方法的局部变量。main方法中的a、b变量作为参数值传入swap方法,实际上是在swap方法栈区中重新产生两个变量a、b,并将main方法栈区中的a、b变量的值分别赋给swap方法栈区中的a、b参数(就是对swap方法的a、b形参进行初始化)。此时,系统存在两个a变量,两个b变量,只是存在于不同的方法栈区中而已。
程序在swap方法中交换a、b两个变量的值,实际上是对图2中灰色覆盖区域的a、b变量进行交换,交换结束后swap方法中输出a、b变量的值,看到a的值为9,b的值为6,此时内存中的存储示意图如图3所示。
对比图3和图2,两个示意图中main方法栈区的a、b值并未有任何改变,程序改变的只是swap方法栈区中的a、b值。
这就是值传递的实质:当系统开始执行方法时,系统为形参执行初始化,就是把实参变量的值赋给方法的形参变量,方法里操作并不是实际的参数变量。
二、参数类型是引用类型的值传递
下面通过一个程序来演练 参数类型是引用类型的值传递的效果:
class DataWrap { public int a; public int b; } public class ReferenceTransferTest { public static void swap(DataWrap dw) { // 下面三行代码实现dw对象的a、b两个Field交换 // 定义一个临时变量来保存dw对象a Field的值 int temp = dw.a; // 把dw对象b Field的值赋给a Field dw.a = dw.b; // 把临时变量temp的值赋给dw对象b Field dw.b = temp; System.out.println("swap方法中,a Field的值是:" + dw.a + ", b Field的值是:" + dw.b); } public static void main(String[] args) { DataWrap dw = new DataWrap(); dw.a = 6; dw.b = 9; swap(dw); System.out.println("交换结束后,a Field的值是:" + dw.a + ", b Field的值是:" + dw.b); } }
swap方法中,a Field的值是:9, b Field的值是:6 交换结束后,a Field的值是:9, b Field的值是:6
程序从main方法开始执行,main方法开始创建了一个DataWrap对象,并定义了一个dw引用变量来指向DataWrap对象,这是一个与基本类型不同的地方。创建一个对象时,系统内存中有两个东西:堆内存中保存对象本身,栈内存中保存了引用该对象的引用变量。接着程序通过引用来操作DataWrap对象,把该对象的a、b两个Field分别赋值给6、9。此时系统内存中的存储示意图如图4所示。
接下来,main方法中开始调用swap方法,main方法并未结束,系统会分别开辟出main和swap两个栈区,用于存放main和swap方法的局部变量。调用swap方法时,dw变量作为实参传入swap方法,同样采用值传递方式:把main方法里的dw变量的值赋给swap方法里的dw形参,从而完成swap方法的dw形参的初始化。值得指出的是:main方法中的dw是一个引用(也就是一个指针),它保存了DataWrap对象的地址值,当把dw的值赋给swap方法的dw形参后,即让swap方法的dw形参也保存了这个地址值,即也会引用到堆内存中的DataWrap对象。图5显示了dw传入swap方法后的存储示意图。
从图5来看,这种参数传递方式是不折不扣的值传递方式,系统一样复制了dw的副本传入swap方法,但关键在于dw只是一个引用变量,所以系统复制了dw变量,但并未复制DataWrap对象 。
当程序在swap方法中操作dw形参时,由于dw只是一个引用变量,故实际操作的还是堆内存中的DataWrap对象。此时,不管操作main方法里的dw变量,还是操作swap方法里的dw变量,其实都是操作它所引用的DataWrap对象,它们操作的是同一个对象。因此,当swap方法中交换dw参数所引用DataWrap对象的a、b两个Field值后,我们看到main方法中的dw变量所引用DataWrap对象的a、b两个Field值也被交换了。
为了更好地证明main方法中的dw和swap方法中的dw是两个变量,我们在swap方法的最好一行增加如下代码:dw=null;
public static void swap(DataWrap dw) { // 下面三行代码实现dw对象的a、b两个Field交换 // 定义一个临时变量来保存dw对象a Field的值 int temp = dw.a; // 把dw对象b Field的值赋给a Field dw.a = dw.b; // 把临时变量temp的值赋给dw对象b Field dw.b = temp; System.out.println("swap方法中,a Field的值是:" + dw.a + ", b Field的值是:" + dw.b); //把dw直接赋值为null,让它不再指向任何有效地址 dw=null; }
从图6来看,把swap方法中的dw赋值为null后,swap方法中失去了DataWrap对象的引用,不可再访问堆内存中的DataWrap对象。但main方法中的dw变量不受任何影响,依然引用DataWrap对象,所以依然可以输出DataWrap对象的a、b Field值。
三、总结
Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本。指向同一个对象,对象的内容可以在被调用的方法中改变,但对象的引用(不是引用的副本)是永远不会改变的。
Java参数,不管是原始类型还是引用类型,传递的都是副本(有另外一种说法是传值,但是说传副本更好理解吧,传值通常是相对传址而言)。
我的Java开发学习之旅------>Java语言中方法的参数传递机制
原文地址:http://blog.csdn.net/ouyang_peng/article/details/46385741