Java面试题:为什么Java中只有值传递?

作者 : 开心源码 本文共3353个字,预计阅读时间需要9分钟 发布时间: 2022-05-13 共211人阅读

最近跟Java中的值传递和引用传递杠上了,一度怀疑人生。查了很多资料,加上自己的了解,终于搞清楚了,什么是值传递和引用传递。也搞明白了,为什么大家都说Java只有值传递,没有引用传递。原来,我一直以来的认知都是错误的。。。

首先,需要理解少量概念性的东西。

形参加实参:

形参,是指在定义函数时使用的参数,目的是用于接收调用该函数时传入的参数。简单了解,就是所有函数(即方法)的参数都是形参。

实参,是指调用函数时,传递给函数的参数。

public static void main(String[] args) {    int num = 3;    printVal(num); //这里num是实参}private static void printVal(int num) {    num = 5; //这里num就是形参}

值传递和引用传递

值传递:是指在调用函数时,将实际参数复制一份传递给函数,这样在函数中修改参数时,不会影响到实际参数。其实,就是在说值传递时,只会改变形参,不会改变实参。

引用传递:是指在调用函数时,将实际参数的地址传递给函数,这样在函数中对参数的修改,将影响到实际参数。

这里,需要特别强调的是,千万不要以为传递的参数是值就是值传递,传递的是引用就是引用传递。也不要以为传递的参数是基本数据类型就是值传递,传递的是对象就是引用传递。 这是大错特错的。以前的我,一直都是这样认为的,现在想来真是太天真了。判断是值传递还是引用传递的标准,和传递参数的类型是没有一毛钱关系的。

下面三种情况,基本上可以涵盖所有情况的参数类型。

当传递的参数是基本数据类型时:

public class TestNum {    public static void main(String[] args) {        int num = 3;        System.out.println("修改前的num值:"+num);        changeValue(num);        System.out.println("修改后的num值:"+num);    }    private static void changeValue(int num) {        num = 5;        System.out.println("形参num值:"+num);    }}

打印结果:

修改前的num值:3形参num值:5修改后的num值:3

可以发现,传递基本数据类型时,在函数中修改的仅仅是形参,对实参的值的没有影响。

需要明白一点,值传递不是简单的把实参传递给形参,而是,实参建立了一个副本,而后把副本传递给了形参。下面用图来说明一下参数传递的过程:

1637794-6fda183412e27ccb.png

图中num是实参,而后创立了一个副本temp,把它传递个形参value,修改value值对实参num没有任何影响。

传递类型是引用类型时:

public class User {    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 User(int age, String name) {        this.age = age;        this.name = name;    }    public User() {    }    @Override    public String toString() {        return "User{" +                "age=" + age +                ", name='" + name + '\'' +                '}';    }}public class TestUser {    public static void main(String[] args) {        User user = new User(18, "zhangsan");        System.out.println("修改对象前:"+user);        changeUser(user);        System.out.println("修改对象后:"+user);    }    private static void changeUser(User user) {        user.setAge(20);        user.setName("lisi");    }}

打印结果:

修改对象前:User{age=18, name='zhangsan'}修改对象后:User{age=20, name='lisi'}

可以发现,传过去的user对象,属性值被改变了。因为,user对象存放在堆里边,其引用存放在栈里边,其参数传递图如下:

1637794-d8b75a7805513e96.jpeg

user是对象的引用,为实参,而后创立一个副本temp,把它传递给形参user1。但是,他们实际操作的都是堆内存中的同一个User对象。因而,对象内容的修改也会表现到实参user上。

传递类型是String类型(Integer等基本类型的包装类等同)

public class TestStr {    public static void main(String[] args) {        String str = new String("zhangsan");        System.out.println("字符串修改前:"+str);        changeStr(str);        System.out.println("字符串修改后:"+str);    }    private static void changeStr(String str) {        str = "lisi";    }}

打印结果:

字符串修改前:zhangsan字符串修改后:zhangsan

咦,看到这是不是感觉有点困惑。按照第二种情况,传递参数是引用类型时,不是可以修改对象内容吗,String也是引用类型,为什么在这又不变了呢?

再次强调一下,传递参数是引用类型,并不代表就是引用传递,其实它还是值传递。此时的 lisi 和上边的 zhangsan 根本不是同一个对象。画图了解下:

图中,str是对象 zhangsan 的引用,为实参,而后创立了一个副本temp,把它传递给了形参str1。此时,创立了一个新的对象 lisi ,形参str1指向这个对象,但是原来的实参str还是指向zhangsan。因而,形参内容的修改并不会影响到实参内容。所以,两次打印结果都是zhangsan。

第三种情况和第二种情况尽管传递的都是引用类型变量,但是解决方式却不一样。第三种情况是创立了一个新的对象,而后把形参指向新对象,而第二种情况并没有创立新对象,操作的还是同一个对象。假如把上边changeUser方法稍作改变,你就会了解:

private static void changeUser(User user) {    //增加一行代码,创立新的User对象    user = new User();    user.setAge(20);    user.setName("lisi");}

运行以上代码,你就会惊奇的发现,最终打印修改前和修改后的内容是一模一样的。
这种情况,就等同于第三种情况。由于,这里的形参和实参引用所指向的对象是不同的对象。因而,修改形参对象内容并不会影响实参内容。

修改对象前:User{age=18, name='zhangsan'}修改对象后:User{age=18, name='zhangsan'}

总结:

从以上三个例子中,我们就能了解了,为什么Java中只有值传递,并没有引用传递。值传递,不管传递的参数类型是值类型还是引用类型,都会在调用栈上创立一个形参的副本。不同的是,对于值类型来说,复制的就是整个原始值的复制。而对于引用类型来说,因为在调用栈中只存储对象的引用,因而复制的只是这个引用,而不是原始对象。

最后,再次强调一下,传递参数是引用类型,或者者说是对象时,并不代表它就是引用传递。引用传递不是用来描述参数的类型的,不要被“引用”这个词本身迷惑了。这就好像我们生活中说的地瓜不是瓜,而是红薯一样。

  1. 参数传递时,是拷贝实参的副本,而后传递给形参。(值传递)
  2. 在函数中,只有修改了实参所指向的对象内容,才会影响到实参。以上第三种情况修改的实际上只是形参所指向的对象,因而不会影响实参。

相关文章:

  • 面试题:Java基础
  • 10道java易错题目
  • 面试题:Integer和int的区别?在什么时候用Integer和什么时候用int
说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Java面试题:为什么Java中只有值传递?

发表回复