zoukankan      html  css  js  c++  java
  • 解惑4:java是值传递还是引用传递

    一、概述

    曾经纠结了很久java的参数传递方式是什么样的,后面粗略的了解了一鳞半爪以后有了大概的印象:“传参数就是值传递,传对象就是引用传递”,后面进一步查找了相关资料和文章以后,发现这么理解是不正确的。

    这里先放结论:

    • java中参数的传递可以理解为都是值传递
    • 基础数据类型传递的是值的拷贝
    • 对象类型是共享对象传递,传递的是地址的拷贝

    二、形参和实参

    要理解参数的传递就必须先理解形参和实参:

    • 形参:就是形式参数,用于定义方法的时候使用的参数,是用来接收调用者传递的参数的。

      形参只有在方法被调用的时候,虚拟机才会分配内存单元,在方法调用结束之后便会释放所分配的内存单元。

      因此,形参只在方法内部有效,所以针对引用对象的改动也无法影响到方法外。

    • 实参:就是实际参数,用于调用时传递给方法的参数

    举个例子:

    public static void main( String[] args ) {
        String string = "Hello";
        //string是实际参数
        sout(string);
    }
    
    public static void sout(String str){
        //str为形式参数
        System.out.println(str);
    }
    

    三、值传递和引用传递与共享对象传递

    1.值传递和引用传递

    理解了实参和形参,以及java对应的数据类型,我们就可以理解值传递和引用传递了。

    • 值传递:方法调用时,实际参数的被传递给对应的形式参数,函数接收的是原始值的一个copy, 此时内存中存在两个相等的基本类型,即实际参数和形式参数,后面方法中的操作都是对形参这个值的修改,不影响实际参数的值

    • 引用传递/址传递:方法调用时,实际参数的地址被传递给方法中相对应的形式参数,函数接收的是原始值的内存地址。在方法执行中,形参和实参内容相同,指向同一块内存地址,方法执行中对引用的操作将会影响到实际对象

    对于这两种方式,网上有一个非常形象的图:

    2.共享对象传递

    但是java的传值策略有点类似于两者的结合,是共享对象传递

    • 共享对象传递:先获取到实际参数的地址,然后将其复制,并把该地址的拷贝传递给被调函数的形式参数。因为参数的地址都指向同一个对象,所以我们称也之为"传共享对象",所以,如果在被调函数中改变了形式参数的值,调用者是可以看到这种变化的。

    这也是之所以说java也是值传递的原因,共享对象传递实际上也是对实参进行拷贝然后赋给形参,但是操作针对的对象不是值而是地址

    由于传递的是地址的拷贝,所以如果你在方法中将这个地址指向了新的对象,实际上是没有任何对方法外是没有任何作用的,举个例子:

    public static void main( String[] args ) {
        Person p = new Person();
        System.out.println("main中:" + p.hashCode());
        change(p);
        System.out.println("main中:" + p.hashCode());
    }
    
    public static void change(Person person){
        person = new Person();
        System.out.println("change中:" + person.hashCode());
    }
    
    //输出
    main中:692404036
    change中:1554874502
    main中:692404036
    

    可以看到在main方法中输出的hashCode指向的都是同一个对象,而change中指向了另一个,可以这么理解:

    • p为指向了第一个Person对象的地址
    • 把p拷贝了一份得到p‘,这里的p’就是change方法中的形参p
    • change中p指向了一个新的Person对象,在change这个函数范围里p指向的就是new出来的第二个Person对象的地址
    • 由于change中的p实际上是main中p的拷贝p‘,所以在change里p'指向的改变对main中的p不会有任何影响

    四、总结

    你在福建有座仓库,给自己配了一把钥匙

    1.三种传递:

    • 值传递:你建了一座一模一样的仓库给别人
    • 引用传递:把你家仓库的钥匙给了别人
    • 共享对象传递:把你家仓库钥匙复刻了一把给别人

    2.共享对象传递的特点:

    • 拷贝的地址与原地址指向同一个内存对象:别人用你复刻的钥匙一样能进出你的仓库
    • 拷贝地址引用对象的改变不影响原地址的引用对象:老王在福建泉州也盖了个一模一样仓库,钥匙和你的一模一样,虽然你的仓库比较有名,但是唯独在泉州提到仓库大家都想到的是老王的仓库。你说这把钥匙能开仓库,在泉州大家想到是这把钥匙能开老王的仓库,在其他城市大家想到是能开你的仓库
  • 相关阅读:
    IDEA的JDBC报错解决
    java注解
    Java反射
    javaIO
    工程师的认知
    前端的一些性能提升
    ES6函数的扩展
    2020新年愿望
    高维护性的javascript
    Chrome Dev tools的几点小技巧
  • 原文地址:https://www.cnblogs.com/Createsequence/p/13439392.html
Copyright © 2011-2022 走看看