浅谈Java到底是值传递还是引用传递呢

 更新时间:2021年06月08日 14:36:00   作者:XH雪浪风尘  
今天带大家学习Java的相关知识,文章围绕着Java到底是值传递还是引用传递展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下

一、前言

最近在看Java核心卷一,也就是这本书:

在这里插入图片描述

在这本书里面也看到了这个问题,Java是值传递还是引用传递,这个问题其实也是很有意思的,之前也看到过这个问题,但是只是依稀记得是值传递,而且网上也有在讨论这个问题的。所以就先说结论吧:是值传递。

二、值传递与引用传递

既然讨论是值传递还是引用传递,那肯定是要知道啥是值传递、引用传递的。

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

所以我们就可以做个简单的比较:

值传递 引用传递 
将参数复制一份传递过去 将参数的实际地址传递过去
不会影响到实际参数 会影响到实际参数

我们在方法中,传递参数类型有两种:基本数据类型(数字、布尔)以及对象引用这两种,所以我们就从这两种类型进行分析。

三、基本数据类型

以数字int为例:

public class Test {
    public static void main(String[] args) {
        Test test=new Test();
        int i=1;
        test.incr(i);
        System.out.println("main中i的值大小为"+i);
    }
    public void incr(int i){
        i=i+1;
        System.out.println("incr中i为"+i);
    }
}

main方法中的结果要么为1,要么为2,如果还是1的话,那么很大可能就是值传递,我们看下输出结果:

incr中i为2
main中i的值大小为1

可以看到,main方法中的值仍为1,我们来看下这个的过程是怎么样的:

在这里插入图片描述

incr方法中虽然对i的值进行了加一操作,但是他只是将值复制了一份,incr方法执行完毕之后,就会被处理掉,并没有改掉原先的值,所以才会在main方法中打印出i还是原先的值。

四、对象引用

基本数据类型其实比较好解释,对象引用其实还是有那么一点迷惑性的,因为有的人可以认为对象引用是引用传递,他可以向方法中传递一个对象,然后在子方法中修改对象的值,就比如下面的这个例子:
例子一:

public class Test {
    public static void main(String[] args) {
        Test test=new Test();
        Student s1=new Student();
        s1.setId(1);
        test.changeId(s1);
        System.out.println("main中的s1id是"+s1.getId());
    }

    public void changeId(Student student){
        student.setId(2);
        System.out.println("changeId中的id为"+student.getId());
    }
   
}
class Student{
    private int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

一个很简单的例子,创建个student对象,只有id这一个字段,将student对象传递到子方法中,执行结果会是什么呢?

changeId中的id为2
main中的s1id是2

可以看到阿,main方法与changeId方法中,他们最后的id都是2,所以有的人就会认为,修改了对象中的值,所以是值传递。

其实我们看上面值传递与引用传递的概念,引用传递是传递的地址,那么我们就假设对象引用是引用传递方式,那么我传递进去两个对象,交换他们的位置是可以改变他们的指向的,接下来我们就来看一下会不会改变:
例子二:

package com.dong.No2;

public class Test {
    public static void main(String[] args) {
        Test test=new Test();
        Student s1=new Student();
        Student s2=new Student();
        s1.setId(1);
        s2.setId(2);
        test.changeId2(s1,s2);
        System.out.println("main中的s1id是"+s1.getId()+","+"s2id是"+s2.getId());
    }

    public void changeId2(Student s1,Student s2){
        Student s3=s1;
        s1=s2;
        s2=s3;
        System.out.println("changeId2中的s1id是"+s1.getId()+",s2id是"+s2.getId());
    }
}
class Student{
    private int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

他的执行结果:

changeId2中的s1id是2,s2id是1
main中的s1id是1,s2id是2

我们发现,这个在子方法中,对象的值是改变了,但是main方法中的值还是原先的样子,那这样就不符合引用传递了,因为他其实并没有改变原先的对象。

如果我们以值传递的观点来解释,那么就可以说的通了,我们传入的两个参数s1、s2在传递过去后,会复制一份为s1复制、s2复制,然后在子方法中,是对这两个复制过后的对象进行的操作,执行完之后,这些复制的对象就会被回收,所以就出现了我们在主方法中,看到这两个对象的值是没有改变的。

事实上也是如此,我们可以同样来解释例子一种,为啥传入了对象,但是主方法中的值却改变了。

我们知道对象这些都是在堆中存储的,我们在向方法中传递的,实际上是这个对象在堆中的地址,我们传递的对象,实际上就是传递的对象的地址:

在这里插入图片描述

因为s1与s1复制都是指向的ox123456,s1复制改变了值,那么s1看到的值也就发生了改变,即使是s1复制最后被回收,ox123456的改变不会恢复。

五、结论

所以Java中的传递只有值传递而没有引用传递,只不过传递为基本数据类型的话,是复制的数值,而对象类型的话,则是复制的对象存放地址。

到此这篇关于浅谈Java到底是值传递还是引用传递呢的文章就介绍到这了,更多相关Java值传递内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java String拼接时的问题汇总

    java String拼接时的问题汇总

    在本篇文章里小编给大家整理的是关于java String拼接时的问题汇总,有需要的朋友们可以参考下。
    2020-02-02
  • 关于MyBatis结果映射的实例总结

    关于MyBatis结果映射的实例总结

    结果集映射主要是为了解决属性名和类型名不一致的问题,下面这篇文章主要给大家介绍了关于MyBatis结果映射的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-05-05
  • Java实现导出Word文档的示例代码

    Java实现导出Word文档的示例代码

    poi-tl是一个基于Apache POI的Word模板引擎,也是一个免费开源的Java类库,你可以非常方便的加入到你的项目中。本文就利用它实现导出Word文档功能,需要的可以参考一下
    2023-02-02
  • Java中线程的等待与唤醒_动力节点Java学院整理

    Java中线程的等待与唤醒_动力节点Java学院整理

    在Object.java中,定义了wait(), notify()和notifyAll()等接口。wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。下面通过本文给大家介绍Java中线程的等待与唤醒知识,感兴趣的朋友一起看看吧
    2017-05-05
  • request如何获取完整url(包括域名、端口、参数)

    request如何获取完整url(包括域名、端口、参数)

    这篇文章主要介绍了request如何获取完整url(包括域名、端口、参数)问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • Java通过PowerMockito和Mokito进行单元测试的实现

    Java通过PowerMockito和Mokito进行单元测试的实现

    PowerMockito和Mockito都是Java语言中的测试框架,用于进行单元测试和集成测试,本文就来详细的介绍一下通过PowerMockito和Mokito进行单元测试,感兴趣的可以了解一下
    2023-08-08
  • debug模式迟迟不能启动问题及解决

    debug模式迟迟不能启动问题及解决

    在使用Debug模式进行代码测试时,由于设置了过多的断点,导致程序加载缓慢甚至无法启动,解决此问题的方法是取消不必要的断点,通过IDE的断点管理功能,检查并移除问题断点,从而优化调试效率,分享此经验希望能帮助遇到相同问题的开发者
    2022-11-11
  • Java实战之网上书店管理系统的实现

    Java实战之网上书店管理系统的实现

    本文将利用Java语言实现网上书店管理系统。其功能一般包括:图书信息管理、用户信息管理、图书购买、图书订单查看、图书添加、图书维护等等,感兴趣的可以了解一下
    2022-06-06
  • 基于SpringBoot实现文件秒传功能

    基于SpringBoot实现文件秒传功能

    在开发Web应用时,文件上传是一个常见需求,然而,当用户需要上传大文件或相同文件多次时,会造成带宽浪费和服务器存储冗余,此时可以使用文件秒传技术通过识别重复文件,本文就给大家介绍了如何基于SpringBoot实现文件秒传功能,需要的朋友可以参考下
    2025-04-04
  • java中的Serializable、transient关键字详解

    java中的Serializable、transient关键字详解

    这篇文章主要介绍了java中的Serializable、transient关键字详解,序列化只会保存属性值,不会保存方法,通过反序列化可以把序列化后的内容恢复成对象,需要的朋友可以参考下
    2023-09-09

最新评论