先说结论,Java就是值传递。

01

在Java中,所有的参数都是按值传递的,即方法得到的是所有参数值的一个副本,而不是原始参数。当我们将一个对象的引用作为参数传递给一个方法时,实际上传递的是该对象的引用的副本。

下面是一个例子来说明这一点:

public class Test {

    public static void main(String[] args) {
        int x = 10;
        changeValue(x);
        System.out.println("x = " + x); // 输出结果:x = 10
        
        String str = "hello";
        changeValue(str);
        System.out.println("str = " + str); // 输出结果:str = hello
        
        Person person = new Person("Jack");
        changeValue(person);
        System.out.println("person.name = " + person.getName()); // 输出结果:person.name = Rose
    }
    
    public static void changeValue(int x) {
        x = 5;
    }
    
    public static void changeValue(String str) {
        str = "world";
    }
    
    public static void changeValue(Person person) {
        person.setName("Rose");
    }
}

class Person {
    private String name;

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

    public String getName() {
        return name;
    }

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

在上面的代码中,我们分别定义了三个方法changeValue,并且在main方法中调用了这三个方法。

  • 第一个changeValue方法接收一个int类型的参数,将其修改为5,但是在main方法中输出的结果依然是原来的值10,说明传递的参数是按值传递的。

  • 第二个changeValue方法接收一个String类型的参数,将其修改为world,但是在main方法中输出的结果依然是原来的值hello,说明传递的参数是按值传递的。

  • 第三个changeValue方法接收一个Person类型的参数,将其名称修改为Rose,并且在main方法中输出该对象的名称也为Rose,说明传递的参数是按值传递的。但是由于传递的是该对象的引用的副本,而不是原始参数,因此我们可以通过该引用访问和修改该对象的属性。

02

那为什么很多人都觉得Java是引用传递,比如对引用类型参数的传递?

相信这也是很多人的疑问。

产生这样的错觉,这很可能是因为Java中对象本身是通过引用来传递的。在Java中,当我们声明一个对象并将其赋值给一个变量时,实际上是创建了一个指向该对象的引用。当我们将该变量传递给一个方法时,实际上传递的是该引用,即指向该对象的地址。因此,在方法内部可以通过该引用来修改该对象的状态。

然而,需要注意的是,虽然引用本身是传递的,但是对于对象本身的修改并不会影响到原始的对象,因为传递的只是地址而不是对象本身。如果我们在方法内部将传入的参数重新赋值为一个新的对象,那么这个新对象只会存在于方法内部,并不会影响到原始的对象。

因此,我们可以说Java中是值传递,但是对于引用类型的参数,传递的是引用的值。

好的,让我们来看一个例子。

假设我们有一个Person类,其中包含姓名和年龄两个属性。现在有一个方法叫做changeAge,在该方法中,我们接收一个Person对象和一个整数作为参数,然后将这个整数赋值给Person对象的年龄属性。代码如下:

public class Person {
    private String name;
    private int age;

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

    public int getAge() {
        return age;
    }
}

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person("Tom", 20);
        int newAge = 30;
        changeAge(p1, newAge);
        System.out.println(p1.getAge()); // 输出 20
    }

    public static void changeAge(Person person, int newAge) {
        person = new Person(person.getName(), newAge);
    }
}

在上面的代码中,我们创建了一个Person对象p1,其年龄为20。然后我们调用changeAge方法,并将p1和一个新的年龄值30传递给该方法。在changeAge方法中,我们通过传入的person参数来获取p1对象,并将其重新赋值为一个新的Person对象,其中年龄为传入的newAge参数。

最后,我们打印出p1对象的年龄,预期输出应该是30。但实际输出却是20。这是因为在changeAge方法中,我们只是修改了传入的person引用指向的对象,而并没有修改p1本身的值。当changeAge方法返回时,p1仍然指向原来的Person对象,其年龄还是20。

因此,我们可以看到,在Java中,虽然引用类型的参数传递的是引用的值,但是这不等同于引用传递。对于传入的引用类型参数,在方法内部对其进行修改只会影响到该引用所指向的对象,而不会影响到原始的对象。

03

看到这里,我知道有的小伙伴肯定坐不住了。

谁说不能改age,我这样写就能改!

    public static void changeAge(Person person, int newAge) {
        person.setAge(newAge);
    }

我也不多废话了,直接告诉你结论:

person仍然是值传递,传递的是引用的值(内存地址),所以看起来像引用传递。

就好像你去配了一把钥匙,也能打开门一样,但是哪怕作用一样,你手里的也是配出来的钥匙,而不是原来的钥匙。

总结

对于基本数据类型,肯定是值传递,没什么好说的。

对于引用类型,仍然是值传递,传递的是引用的值(内存地址),所以看起来像引用传递。

posted on 2023-05-25 14:12  剽悍一小兔  阅读(33)  评论(0编辑  收藏  举报  来源