Java值传递与引用传递的区别

Java值传递与引用传递的区别Java 值传递与引用传递文章目录 Java 值传递与引用传递前景实参与形参值传递与引用传递 Java 中的值传递总结前景关于这个问题 引发过很多广泛的讨论 看来很多程序员对于这个问题的理解都不尽相同 甚至很多人理解的是错误的 还有的人可能知道 Java 中的参数传递是值传递 但是说不出来为什么 在开始深入讲解之前 有必要纠正一下大家以前的那些错误看法了 如果你有以下想法 那么你有必要好好阅读本文 错误理解一 值传递和引用传递 区分的条件是传递的内容 如果是个值 就是值传递 如果是个引用 就是引用传递 错误

Java值传递与引用传递

前景

  • 错误理解一:值传递和引用传递,区分的条件是传递的内容,如果是个值,就是值传递。如果是个引用,就是引用传递。
  • 错误理解二: Java是引用传递。
  • 错误理解三:传递的参数如果是普通类型,那就是值传递,如果是对象,那就是引用传递。

实参与形参

public static void main( String[ ] args) { 
    ParamTest pt = new ParamTest(); pt.sout( "Hollis");//实际参数为Hollis } public void sout( String name) { 
   /!形式参数为name system.out.println(name); } 

实际参数是调用有参方法的时候真正传递的内容,而形式参数是用于接收实参内容的参数。

值传递与引用传递

上面提到了,当我们调用一个有参函数的时候,会把实际参数传递给形式参数。但是,在程序语言中,这个传递过程中传递的两种情况,即值传递和引用传递。我们来看下程序语言中是如何定义和区分值传递和引用传递的。

值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

有了上面的概念,然后大家就可以写代码实践了,来看看Java中到底是值传递还是引用传递,于是,最简单的一段代码出来了:

public static void main( String[] args) { 
    ParamTest pt = new ParamTest(); int i = 10; pt.pass(i); System.out.println( "print in main , i is " +i); } public void pass(int j){ 
    j = 20; system.out.println( "print in pass , j is " + j); } 

上面的代码中,我们在pass方法中修改了参数j的值,然后分别在pass方法和main方法中打印参数的值。输出结果如下:

print in pass , j is 20 print in main , i is 10 
public static void main(String[ ] args) { 
    ParamTest pt = new ParamTest(); User hollis = new User(); hollis.setName( "Hollis"); hollis.setGender("Male"); pt.pass(hollis); system.out.println( "print in main , user is " + hollis); } public void pass(User user) { 
    user.setName( "hollischuang"); System.out.println( "print in pass , user is " + user); } 

同样是一个pass方法,同样是在pass方法内修改参数的值。输出结果如下:

print in pass , user is User{ 
   name='hollischuang', gender='Male '} print in main , user is User{ 
   name='hollischuang' , gender='Male '} 
public static void main( string[] args) { 
    ParamTest pt = new ParamTest(); string name = "Hollis"; pt.pass(name ) ; System.out.println( "print in main , name is " + name); } public void pass(string name) { 
    name = "hollischuang"; system.out.println( "print in pass , name is " + name); } 

上面的代码输出结果为

print in pass , name is hollischuangprint in main , name is Hollis 

这又作何解释呢?同样传递了一个对象,但是原始参数的值并没有被修改,难道传递对象又变成值传递了?

Java中的值传递

上面,我们举了三个例子,表现的结果却不一样,这也是导致很多初学者,甚至很多高级程序员对于Java的传递类型有困惑的原因。其实,我想告诉大家的是,上面的概念没有错,只是代码的例子有问题。来,我再来给大家画—下概念中的重点,然后再举几个真正恰当的例子。

值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

那么,我来给大家总结一下,值传递和引用传递之前的区别的重点是什么。

值传递 引用传递
根本区别 会创建副本 copy 不创建副本
所有 函数中无法改变原始对象 函数中可以改变原始对象
public static void main(String[ ] args){ 
    ParamTest pt = new ParamTest(); User hollis = new User(); hollis.setName( "Hollis"); hollis.setGender("Male" ); pt.pass(hollis); system.out.println("print in main , user is " + hollis); public void pass(User user) { 
    user = new User(); user.setName( "hollischuang"); user.setGender( "Male"); system.out.println( "print in pass , user is " + user); 

上面的代码中,我们在pass方法中,改变了user对象,输出结果如下:

print in pass , user is User{ 
   name='hollischuang ' , gender='Male '} print in main , user is User{ 
   name='Hollis', gender= 'Male '} 

我们来画一张图,看一下整个过程中发生了什么,然后我再告诉你,为啥Java中只有值传递。

Java值传递与引用传递的区别

Java值传递与引用传递的区别

Java值传递与引用传递的区别

所以说,Java中其实还是值传递的,只不过对于对象参数,值的内容是对象的引用。

总结

无论是值传递还是引用传递,其实都是一种求值策略(Evaluation strategy)。在求值策略中,还有一种叫做按共享传递。其实Java中的参数传递严格意义上说应该是按共享传递。

按共享传递,是指在调用函数时,传递给函数的是实参的地址的拷贝(如果实参在栈中,则直接拷贝该值)。在函数内部对参数进行操作时,需要先拷贝的地址寻找到具体的值,再进行操作。如果该值在栈中,那么因为是直接拷贝的值,所以函数内部对参数进行操作不会对外部变量产生影响。如果原来拷贝的是原值在堆中的地址,那么需要先根据该地址找到堆中对应的位置,再进行操作。因为传递的是地址的拷贝所以函数内对值的操作对外部变量是可见的。

所以函数内部对参数进行操作不会对外部变量产生影响。如果原来拷贝的是原值在堆中的地址,那么需要先根据该地址找到堆中对应的位置,再进行操作。因为传递的是地址的拷贝所以函数内对值的操作对外部变量是可见的。

//本文借鉴于知乎Holis先生

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/232607.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 粘包问题怎么解决_包带粘手怎么处理

    粘包问题怎么解决_包带粘手怎么处理如何解决粘包问题粘包就是连续向对端发送两个或者两个以上的数据包,对端在一次收取中受到的数据包数量可能大于1个,当大于1个时,可能时几个包加上某个包的部分,这这干脆几个完整的包在一起。当然,也可能收到的数据只是一个包的部分,这种情况一般也叫做半包。无论是半包问题还是粘包问题,因为TCP是流式数据,所以其解决思路还是从收到的数据中把包与包的边界区分出来。如何区分,有以下三种办法。固定包长的数据包。固定包长,即每个协议包的长度都是固定的。假如我们规定每个协议包的大小都是64字节,每收满64字节,就取出来

    2022年8月11日
    9
  • 怎么安装linux和win10双系统,在Win10下安装Linux双系统的方法

    怎么安装linux和win10双系统,在Win10下安装Linux双系统的方法虽然Win10正式版发布的时间并不长,但是现在使用这个新系统的用户已经非常多了。而最近有位用户因为工作需求,想要在全新的windows10系统中安装Linux双系统。那么,这该如何操作呢?下面,小编就给大家分享下在Win10下安装Linux双系统的具体方法。具体方法如下:不管您要安装哪种Linux系统,首先给硬盘划分一个空白分区。win8.1-14、准备LinuxMint启动盘启动电脑,进入…

    2022年7月24日
    13
  • Python定义函数

    Python定义函数其他形式1:1、定义函数deftest4(a=()):print('################test4################')print(type(a

    2022年7月5日
    25
  • C++容器和迭代器

    C++容器和迭代器一 顺序容器 vector1 1 容器是什么在 C 中 容器被定义为 在数据存储上 有一种对象类型 它可以持有其他对象或指向其他对象的指针 这种对象类型就叫做容器 简单理解 即容器就是保存其他对象的对象 而且 这种 对象 还有处理 其他对象 的方法 容器是随着面向对象语言的诞生而提出的 它甚至被认为是早期面向对象语言的基础 现在几乎所有面向对象语言中都伴随着一

    2025年9月25日
    4
  • C++封装、继承、多态

    C++封装、继承、多态C 封装继承多态总结面向对象的三个基本特征面向对象的三个基本特征是 封装 继承 多态 其中 封装可以隐藏实现细节 使得代码模块化 继承可以扩展已存在的代码模块 类 它们的目的都是为了 代码重用 而多态则是为了实现另一个目的 接口重用 封装

    2025年10月26日
    6
  • java内存模型介绍[通俗易懂]

    java内存模型介绍[通俗易懂]####Java内存模型Java内存模型描述了Java虚拟机和计算机内存之间是如何协同工作的。一个Java虚拟机也是一个完整的计算机的模型,因此,这个模型自然也包含了内存模型。如果你想写出表现良好的并发程序就必须理解Java内存模型。Java内存模型描述了不同线程间如何和何时看到被其他线程修改的共享变量以及在需要时如何同步访问共享变量。原来的Java内存模型存在很多不足,所以在Java5时进行了修改。这个一直使用至今。####Java内存模型每个运行在Java虚拟机中的线程都拥有自己的线程栈。这

    2022年7月8日
    23

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号