Java值传递还是引用传递?

·  阅读 1871

从我实习面试开始就有在面试中遇到过这个问题:Java是值传递还是引用传递?

当时的我只会背背面试题,但是网上的答案有些还是错的,导致我决心写这一篇文章。

虽然网上已经有很多文章珠玉在前,但是我还是想写一篇我自己的文章,如果写的不好,请见谅

文章开始之前我们还是来解答Java是值传递还是引用传递?这个问题吧!答案自然是:Java是值传递

给定结论后我们再来解释一下什么叫 值传递&引用传递
  • 值传递:值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

  • 引用传递:引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

以下图片来自百度百科

在这里插入图片描述

在这里插入图片描述

上代码证明:

/**
 * 证明java值传递demo
 *
 * @author miao
 */
public class PassValueDemo {

    public static void main(String[] args) {

        int a = 1;
        String str = "1";
        User user = new User("阿花", 6);

        System.out.println("调用方法前a为:" + a);
        System.out.println("调用方法前str为:" + str);
        System.out.println("调用方法前user为:" + user);

        System.out.println("------------------------------------------");
        convert(a, str, user);
        System.out.println("------------------------------------------");

        System.out.println("调用方法后a为:" + a);
        System.out.println("调用方法后str为:" + str);
        System.out.println("调用方法后user为:" + user);
    }

    private static void convert(int a, String str, User user) {
        a = 2;
        str = "2";
        user.setAge(9);
        user.setUsername("大壮");

        System.out.println("调用方法中a为:" + a);
        System.out.println("调用方法中str为:" + str);
        System.out.println("调用方法中user为:" + user);
    }

}

/**
 * @author miao
 */
class User {

    public String username;

    public int age;

    public User(String username, int age) {
        this.username = username;
        this.age = age;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                '}';
    }
}
复制代码

程序的执行结果:

调用方法前a为:1
调用方法前str为:1
调用方法前user为:User{username='阿花', age=6}
------------------------------------------
调用方法中a为:2
调用方法中str为:2
调用方法中user为:User{username='大壮', age=9}
------------------------------------------
调用方法后a为:1
调用方法后str为:1
调用方法后user为:User{username='大壮', age=9}
复制代码

我们可以看到,身为基本类型的int和被final修饰的String并没有改变,但是引用类型User改变了,所以,网上就有人得出了结论:java针对基本类型是值传递,对于引用类型是引用传递但是!!!!这是错误的结论,不相信的话,我在上面的代码中加一行代码,就知道为什么这个是错的结论了

在convert()方法中str = "2";下面增加一行user = new User("小美", 18),让我们看看这样的结果是什么?

在这里插入图片描述

程序的执行结果:

调用方法前a为:1
调用方法前str为:1
调用方法前user为:User{username='阿花', age=6}
------------------------------------------
调用方法中a为:2
调用方法中str为:2
调用方法中user为:User{username='大壮', age=9}
------------------------------------------
调用方法后a为:1
调用方法后str为:1
调用方法后user为:User{username='阿花', age=6}
复制代码
从上述结果可以看出,当我们在 convert 方法中添加 user = new User("小美", 18)之后,“引用传递”就突然变值传递了?为什么?

这是因为,在 Java 语言中本质上只有值传递,也就说 Java 的传参只会传递它的副本,并不会传递参数本身。

即传入convert()时的user为 User user 的副本,指向同一个new User("阿花", 6)的堆地址,

当执行user = new User("小美", 18)时,指向的堆内存改变了,所以再进行任何操作都跟之前的堆地址没关系了,即证实了,传递的是一个副本。

未执行user = new User("小美", 18)之前

在这里插入图片描述

执行user = new User("小美", 18)之后

在这里插入图片描述

总结:通过本文的内容,我们可以得出:在 Java 语言中只有值传递,方法传参时只会传递副本信息而非原内容。我们还知道了基础数据类型会直接生成到栈上,而对象或数组则会在栈和堆上都生成信息,并将栈上生成的引用,直接指向堆中生成的数据

分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改