`

重谈Java的中的参数传递

阅读更多

      最近在复习Java的基础知识,看到自己以前的技术博客里谈到Java中关于参数传递的问题,分析得不够准确,决定再总结一番。

      Java里方法的参数传递方式只有一种:值传递。值传递,就是将实际参数值的副本(复制品)传入方法内,而参数本身不会受到任何影响。

 public class PrimitiveTransferTest
      {
            public static void swap(int a,int b)
             {
                     int temp=a;
                     a=b;
                     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;

         从运行结果可以看出,main方法里面的变量a和b,并不是swap方法里面的a和b。,也就是说swap方法的a和b只是main方法里面变量a和b的复制品。

 Java程序从main方法开始执行,main方法开始定义了a、b两个局部变量,当程序执行swap方法时,系统进入swap方法,并将main方法中的a、b变量作为参数值传入swap方法,传入swap方法的只是a/b的副本,而不是a、b本身,进入swap方法后系统产生了4个变量,main栈区的a和b,swap栈区的a和b。

        在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,一个是main方法中的a、b,程序只是改变的是swap方法中的a、b,而main方法中的a、b并没有改变。这就是值传递的实质:当系统开始执行方法时,系统为形参执行初始化,就是把实参变量的值赋给方法的形参变量,方法里操作的并不是实际的实参变量。

       前面是基本类型的参数传递,Java对于引用类型的参数传递,一样采用的是值传递方式。

 class DataWrap
       {
            public int a;
            public int b;
       }
       public class ReferenceTransferTest
       {
            public static void swap(DataWrap dw)
            {
                     int tmp=dw.a;
                     dw.a=dw.b;
                     dw.b=tmp;
                     System.out.println("swap方法里,a 属性的值是"+dw.a+";b属性的值是"+dw.b);
            }
            public static void main(String args[])
            {
                    DataWrap dw=new DataWrap();
                    dw.a=6;
                    dw.b=9;
                    swap(dw);
                    System.out.println("交换结束后,a属性的值是"+dw.a+";b属性的值是"+dw.b);
            }
  }

 运行结果:

     swap方法里,a属性的值是9;b属性的值是6

     交换结束后,a属性的值是9;b属性的值是6

      从运行结果来看,swap方法和main方法的a、b两个属性值都被交换了,这很容易造成一种错觉:调用swap方法时,传入swap方法的就是dw对象本身,而不是它的复制品。但这只是一种错觉。

      程序从main方法开始执行,main方法开始创建了一个DataWrap对象,并定义了一个dw引用变量来指向DataWrap对象,这是一个与基本类型不同的地方。创建一个对象时,系统内存中有两个东西:堆内存中保存了对象本身,栈内存中保存了引用该对象的引用变量。接下来,main方法中开始调用swap方法,main方法并未结束,系统会分别开辟出main和swap两个栈区,用于存放main和swap方法的局部变量。调用swap方法时,dw变量作为实参传入swap方法,同样采用值传递方式:把main方法里dw变量的值赋给swap方法里dw形参,从而完成swap方法的单位形参的初始化。值得指出的是,main方法的dw是一个引用,它保存了DataWrap对象的地址值,当把dw的值赋给swap方法的dw形参后,即让swap方法的dw形参也保存这个地址值,即也会引用到堆内存中的DataWrap对象。当程序在swap方法中操作dw形参时,由于dw只是一个引用变量,故实际操作的还是堆内存中的DataWrap对象。此时,不管是操作main方法里的dw对象,还是操作swap方法里的dw参数,起始都是操作它所引用的DataWrap对象,它们操作的是同一个对象。因此,当swap方法中交换dw参数所引用的DataWrap对象的a、b两个属性时,我们可以看到main方法中dw变量所引用的DataWrap对象的a、b两个属性值也被交换了。

       为了更好地证明main方法中的dw和swap方法中的dw是两个变量,我们在swap方法的最后一行增加如下代码:

      dw=null;//把dw直接赋值为null,让它不再指向任何有效地址

      然后,main方法调用了swap方法后,再次访问dw变量的a、b两个属性,依然可以输出9、6。把swap方法中的dw赋值为null后,swap方法中失去了DataWrap的引用,不可在访问堆内存中的DataWraper对象。但main方法中的dw变量不受任何影响,依然引用DataWrap对象,所以依然可以输出DataWrap对象的a、b属性值。

分享到:
评论

相关推荐

    浅谈Java中方法参数传递的问题

    下面小编就为大家带来一篇浅谈Java中方法参数传递的问题。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    浅谈Java中的参数传递问题

    主要介绍了Java中的参数传递问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    浅谈JavaScript 函数参数传递到底是值传递还是引用传递

    那么JS的参数传递到底是怎么回事呢?事实上以下的演示也完全可以用于Java 首先来一个比较简单的,基本类型的传递: function add(num){ num+=10; return num; } num=10; alert(add(num)); aelrt(num); //...

    浅谈JAVA内存分配与参数传递

    主要介绍了JAVA内存分配与参数传递,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    JAVA入门1.2.3:一个老鸟的JAVA学习心得 PART1(共3个)

    3.4 小结:基本数据类型—— Java中一切数据和运算的基础 63 3.5 习题 65 第4章 Java中的程序执行流程 67 教学视频:1小时57分钟 4.1 顺序执行 67 4.2 使用if-else让程序懂得判断 68 4.2.1 if语句 68 4.2.2 ...

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    3.4 小结:基本数据类型—— Java中一切数据和运算的基础 63 3.5 习题 65 第4章 Java中的程序执行流程 67 教学视频:1小时57分钟 4.1 顺序执行 67 4.2 使用if-else让程序懂得判断 68 4.2.1 if语句 68 4.2.2 ...

    Java入门教程(微学苑)-part1

    3.16 作为参数传递 51 3.17 Java方法重载 52 3.18 Java类的基本运行顺序 53 3.19 Java包装类、拆箱和装箱详解 54 3.20 包装类的应用 54 3.20.1.1 1) 实现 int 和 Integer 的相互转换 54 3.20.1.2 2) 将字符串转换为...

    解决java页面URL地址传输参数乱码的方法

    主要介绍了解决java页面URL地址传输参数乱码的方法,URL地址参数乱码问题,算是老话重谈了吧!需要的朋友可以参考下

    21天学通Java-由浅入深

    101 6.3.2 成员变量的初始化 102 6.4 局部变量 105 6.4.1 局部变量的创建和初始化 105 6.4.2 局部变量和成员变量的区别 106 6.5 方法 106 6.5.1 方法的创建和参数 106 6.5.2 方法参数的传递 108 6.6 对象引用的使用 ...

    基于Java 谈回调函数

    回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数

    30天搞定Java–day9

    文章目录每日一考和复习补充知识点面向对象再谈方法方法的重载可变形参的方法方法参数的值传递机制递归算法(暂时了解) 每日一考和复习 每日一考 面向对象思想编程内容的三条主线分别是什么 类及类的成员:属性、方法...

    浅谈javascript中的call、apply、bind

    该方法可以传递一个thisArgs参数和一个参数列表,thisArgs指定了函数在运行期的调用者,也就是函数中的this对象,而参数列表会被传入调用函数中。thisArgs的取值有以下4种情况: (1) 不传,或者传null,undefined,...

    JSTL详细标签库介绍

    <BR>Java使用和C++类似的异常处理<BR>1、处理错误的方法有很多流行方法<BR>2、一般方法是把程序处理代码段分散到系统代码中,在可能发生错误的地方处理错误优点:便于程序员能够条理的看到程序中异常的处理缺点:...

    c#学习笔记.txt

    如果没有ref,out则默认为值传递,虽然可以在方法中修改这个参数的值,但是修改后的值不会还会到调用该方法的程序中. params :params 关键字可以指定在参数数目可变处采用参数的方法参数 ref :引用传递 out : 7, ...

    我的编程感悟(中文PDF)(共37M二分卷)分卷二

    9.2.3 函数调用的参数传递 244 9.2.4 临时变量的堆栈使用 244 9.2.5 代码生成 244 9.2.6 异常 244 9.2.7 inline 245 9.2.8 多态性 245 9.2.9 标准库的差异 245 9.2.10 动态内存分配 245 9.3 优雅的C++ 246 9.3.1 ...

    我的编程感悟(中文PDF)(共37M二分卷)分卷一

    9.2.3 函数调用的参数传递 244 9.2.4 临时变量的堆栈使用 244 9.2.5 代码生成 244 9.2.6 异常 244 9.2.7 inline 245 9.2.8 多态性 245 9.2.9 标准库的差异 245 9.2.10 动态内存分配 245 9.3 优雅的C++ 246 9.3.1 ...

    C++内存管理.doc

    1.1.5 指针参数是如何传递内存的? 1.1.6 杜绝“野指针” 1.1.7 有了malloc/free为什么还要new/delete? 1.1.8 内存耗尽怎么办? 1.1.9 malloc/free的使用要点 1.2 C++中的健壮指针和资源管理 1.2.1 第一条规则...

    net学习笔记及其他代码应用

    6.如果在一个B/S结构的系统中需要传递变量值,但是又不能使用Session、Cookie、Application,您有几种方法进行处理? 答 : this.Server.Transfer 7.请编程遍历页面上所有TextBox控件并给它赋值为string.Empty? ...

    Python核心编程第二版(ok)

     8.10 再谈else语句   8.11 迭代器和iter()函数   8.11.1 什么是迭代器   8.11.2 为什么要迭代器   8.11.3 如何迭代   8.11.4 使用迭代器   8.11.5 可变对象和迭代器   8.11.6 如何创建...

    Python核心编程第二版

     8.10 再谈else语句   8.11 迭代器和iter()函数   8.11.1 什么是迭代器   8.11.2 为什么要迭代器   8.11.3 如何迭代   8.11.4 使用迭代器   8.11.5 可变对象和迭代器   8.11.6 如何创建...

Global site tag (gtag.js) - Google Analytics