Contents

为什么说Java没有引用传参

1.基本类型的情况

public class Test {
    public static void main(String[] args) {
        int x = 10;
        System.out.println("调用前: " + x); // 输出 10
        changeValue(x);
        System.out.println("调用后: " + x); // 输出 10,原始值x未改变
    }

    public static void changeValue(int num) {
        num = 20; // 这里修改的是副本num,与main方法中的x无关
    }
}

通过上面的例子,毫无疑问基本类型是值传递。

详细过程是这样的:main方法的栈帧存储了x=10,调用changeValue方法后,changeValue的栈帧存储了num=10,修改num=20只是修改了changeValue栈帧的数据。

2.对象引用的情况

public class Test {
    public static void main(String[] args) {
        Person person = new Person("Alice");
        System.out.println("调用前: " + person.name); // 输出 Alice
        reassignPerson(person);
        System.out.println("调用后: " + person.name); // 输出 Alice!对象没有被重新赋值
    }

    public static void reassignPerson(Person p) {
        p = new Person("Bob"); // 试图让p指向一个新对象
        // 这里只是让副本p指向了新的地址(0x2000),而main中的person依然指向旧的地址(0x1000)
    }
}

上面代码的例子和基本类型的情况一样,很好理解。

下面给出一种容易误解的情况。

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

public class Test {
    public static void main(String[] args) {
        Person person = new Person("Alice");
        System.out.println("调用前: " + person.name); // 输出 Alice
        changeName(person);
        System.out.println("调用后: " + person.name); // 输出 Bob!对象的状态被改变了
    }

    public static void changeName(Person p) {
        p.name = "Bob"; // 这里成功修改了对象的内部状态
    }
}

为什么这里又成功改变了,main方法的栈帧存储了person->0x1000(内存地址)这样的键值对,changeName方法的栈帧存储了p->0x1000的键值对。调用p.name其实修改了同一个内存地址对象的数据。

而之前的例子p = new Person(“Bob”);相当于让新方法栈帧的键p的值变了一个内存地址,对person没有任何影响。

3.额外注意的情况

基本类型在栈中直接存的值,但是基本类型的数组不是。数组是特殊的对象引用,在栈中存储的键值对也是地址。