背景

最近在学习Java,我一直有一个疑惑——Java中的传参究竟是什么方式?pass by value?pass by reference?还是会变化?在PL课上,老师讲到了如下的问题:

image-20210328204649012

在这个问题中,答案又应该是什么呢?

思考与解答

首先说结论,我认为Java中的传参都可以看做是pass by value;如果参数是一个对象,那么实际上传递的就是一个指向对象的指针的拷贝。

我们看这样一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package JavaPlayGround;

public class Main {
public static void main(String[]args){
Dog myDog = new Dog();
myDog.setAge(2);
System.out.println(myDog.getAge()); // 2
fooByModify(myDog);
System.out.println(myDog.getAge());// 11

myDog.setAge(2);
fooByAssign(myDog);
System.out.println(myDog.getAge());// 2
}

public static void fooByModify(Dog d){
d.setAge(11);
}

public static void fooByAssign(Dog d){
d = new Dog();
d.setAge(11);
}
}

在上面的例子里,fooByModifyfooByAssign分别对传入的对象进行修改/赋值,而只有前者真正改了原先的对象,后者则对原先的对象没有任何影响。

我的理解如下:

不妨假设myDog指向地址3,那么调用fooByModify时,d也指向地址3(相当于复制了myDog的地址),故而之后的改变都会影响到地址3的myDog。

在调用fooByAssign时,事情有所不同。d一开始指向地址3,但是随后被赋值(记住,此处的d和myDog没有关系,它只是保存了一个地址罢了),故而d指向了一个新的地址,之后的修改也就自然没有任何变化了。

至于PL课上提出的问题,语焉不详(不清楚调用constructor之后的内部行为),无法给出详尽的解释。

参考

stackoverflow上的讨论