ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

为什么Java中只有值传递?

2021-11-20 20:34:22  阅读:175  来源: 互联网

标签:为什么 Java String 传递 实参 public name


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内存区域。

标签:为什么,Java,String,传递,实参,public,name
来源: https://blog.csdn.net/zxlzxcvbnm/article/details/121444939

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有