zoukankan      html  css  js  c++  java
  • 我的Java开发学习之旅------>Java语言中方法的參数传递机制

          

    实參:假设声明方法时包括来了形參声明,则调用方法时必须给这些形參指定參数值,调用方法时传给形參的參数值也被称为实參。

         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

    从上面运行结果来看,在swap方法里,a、b两个Field值被交换成功。不仅如此,main方法里swap方法运行结束后,a、b两个Field值也被交换了。这非常easy造成一个错觉:调用swap方法时。传入swap方法的就是dw对象本身,而不是它的复制品。可是这不过一种错觉,以下还是结合示意图来说明程序的运行过程。

    程序从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;
    	}

    运行上面改动后的代码结果是swap方法中的dw变量不再指向不论什么有效内存,程序其它地方不做不论什么改动。

    main方法调用swap方法后。再次訪问dw变量a、b两个Field,依旧能够输出9、6。可见,main方法中的dw变量没有收到不论什么影响。

    实际上,当swap方法中添加dw=null;代码后,内存中的存储示意图如图6所看到的。

    从图6来看,把swap方法中的dw赋值为null后,swap方法中失去了DataWrap对象的引用,不可再訪问堆内存中的DataWrap对象。但main方法中的dw变量不受不论什么影响,依旧引用DataWrap对象。所以依旧能够输出DataWrap对象的a、b Field值。


    三、总结


          Java 编程语言仅仅有值传递參数

    当一个对象实例作为一个參数被传递到方法中时,參数的值就是该对象的引用一个副本。指向同一个对象,对象的内容能够在被调用的方法中改变。但对象的引用(不是引用的副本)是永远不会改变的。

      Java參数,无论是原始类型还是引用类型。传递的都是副本(有第二种说法是传值,可是说传副本更好理解吧,传值一般是相对传址而言)。

      假设參数类型是原始类型。那么传过来的就是这个參数的一个副本,也就是这个原始參数的值,这个跟之前所谈的传值是一样的。假设在函数中改变了副本的值不会改变原始的值.
      假设參数类型是引用类型。那么传过来的就是这个引用參数的副本。这个副本存放的是參数的地址。假设在函数中没有改变这个副本的地址。而是改变了地址中的值。那么在函数内的改变会影响到传入的參数。假设在函数中改变了副本的地址,如new一个。那么副本就指向了一个新的地址。此时传入的參数还是指向原来的地址,所以不会改变參数的值。

                            

                     ========以上内容出处为李刚老师的《疯狂Java讲义》=======




    ==================================================================================================

      作者:欧阳鹏  欢迎转载。与人分享是进步的源泉!

      转载请保留原文地址http://blog.csdn.net/ouyang_peng

    ==================================================================================================



  • 相关阅读:
    hdu 5795 A Simple Nim 博弈sg函数
    hdu 5724 Chess 博弈sg+状态压缩
    hdu 3094 A tree game 树上sg
    2017"百度之星"程序设计大赛
    hdu 6134 Battlestation Operational 莫比乌斯反演
    HDU 6143 Killer Names DP+快速密
    HDU 6107 Typesetting 倍增
    HDU 6096 String 排序 + 线段树 + 扫描线
    HDU 6086 Rikka with String AC自动机 + DP
    HDU 6073 Matching In Multiplication dfs遍历环 + 拓扑
  • 原文地址:https://www.cnblogs.com/wgwyanfs/p/6878916.html
Copyright © 2011-2022 走看看