为什么说Java没有引用传参
Contents
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.额外注意的情况
基本类型在栈中直接存的值,但是基本类型的数组不是。数组是特殊的对象引用,在栈中存储的键值对也是地址。