为什么Java中只有值传递?

1、必知概念:

  • 实参:方法被调用时传入的实际值。
  • 形参:在定义方法时括号内定义的参数列表即为形参,它用来接收方法调用时传入的实参。
  • 值传递:当方法被调用时,实参通过形参将其副本传入方法内,接下来对形参的操作就是在对实参副本的操作,并不会影响实参本身。
  • 引用传递:当方法被调用时,实参的地址值通过形参将其传入方法内,所以对形参的改变就会映射到实参上。

    注意:值传递与引用传递的区别并不在于被传递参数的类型,也就是说,并不是传入的参数是基本数据类型就是值传递,同理,并不是传入的参数是引用类型就是引用传递。

2、Java中只有值传递的原因:

  • 当形参为基本数据类型时:
public class Test {
    public static void main(String[] args) {
        int num = 9;
        System.out.println("修改前的实参为:" + num);
        change(num);
        System.out.println("修改后的实参为:" + num);
    }

    private static void change(int temp) {
        System.out.println("传入的形参为:" + temp);
        temp++;
        System.out.println("修改后的形参为:" + temp);
    }
}

    可以看出,这个过程虽然改变了形参,但是并没有改变实参的值,所以说是一次值传递过程。接下来就按照Java内存区域进行进一步分析:

    当程序启动时,首先执行main方法,此时就会在本地方法栈中创建一个关于main方法的栈帧进行压栈,栈帧中包含局部变量表(目前仅有num)及其他信息,因为在main方法中调用了change方法,所以要创建一个关于change方法的栈帧再次压栈,如下图所示,

    小结:修改的值是main中传入的num副本值,所以并不会修改num本身。

  • 当形参为引用类型时:
public class TestUser {
    public static void main(String[] args) {
        Person person = new Person(10, "一诺");
        System.out.println("修改前的实参为:" + person);
        change(person);
        System.out.println("修改后的实参为:" + person);
    }

    private static void change(Person p) {
        p.setAge(100);
        p.setName("Cat");
    }
}
public class Person {
    private int age;
    private String name;
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

    Amazing,为什么Person的属性发生了改变,不是值传递吗?不是不改变实参值吗?那么我们就通过Java内存区域来进一步分析:

    可以看出,传递的参数并不是Person对象的具体值,而是它的地址值,所以实参、形参指向的是堆内存中的同一个Person对象,这样我们对形参的修改就会体现在实参上。

    这样理解是没问题,但是我又想了一下,这样通过对象的地址值改变对象属性,这不是引用传递吗?不是说Java中只有值传递吗?带着这个疑问,我又反复看了好多次值传递、引用传递的概念,值传递每次传递的都是实参的副本啊,那要是顺着这条线想下去,那么change中p的值就是person地址值(0x11)的副本值呗,这样就可以解释了上述这个过程是值传递的过程了(不知道这样理解对不对,不对的话还请大家指正~)。

  • 当形参为String等不可变类(Integer等包装类)时:
public class TestString {
    public static void main(String[] args) {
        String str = new String("孙行者");
        System.out.println("字符串修改前:" + str);
        change(str);
        System.out.println("字符串修改后:" + str);
    }

    private static void change(String str) {
        str = "行者孙";
    }
}

    ???为什么又和第二种情况不一样???String不是也是引用类型吗?怎么会出现这种情况呢?带着充满问号的脑袋,接着来按照Java内存区域进一步分析吧:

    可以看出,确实是将实参的副本传入给方法内,但是在change方法中做了一个 str = "行者孙" 的操作,因为String是不可变类,它一旦初始化就不可以再更改值了,因此这个操作是重新实例化了一个String对象,str也由 0x11 变为了 0x10,而0x11所指向的值没有改变,所以自然main方法中的str值不会变啦~

参考:

总结:

    站在巨人的肩膀上才能看的更远,很庆幸能在网上找到前辈们写的文章来解答我的疑惑,同时也希望自己总结的文章能够帮助到别人。而对于这个本文分享的问题,之前我也很不理解为什么Java中只有值传递,但是在了解完Java内存区域后再看这些就很好理解了,在这篇文章我也没有很详细的介绍这部分内容,所以还是推荐对此问题有疑惑的朋友先去了解一下Java内存区域。

  • 3
    点赞
  • 17
    收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:技术黑板 设计师:CSDN官方博客 返回首页
评论 2

打赏作者

会编程的林俊杰

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值