这是一篇译文,原文:
https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value
如果你看不完,或者看不懂,请直接看后记的结论。
我过去一直以为 java 是pass-by-reference但是我见了一个帖子说不是的。我觉得自己不明白其中的区别,解释是什么?
请记住 java 一直是值传递 。
但是很不幸,他们决定把一个对象的地址称为reference.实际上我们可以这样说:
当我们把一个对象的值传递过去的时候,我们其实就是在传递它的引用(reference)
大概可能对初学者, 这一点让他们会感到困惑
来吧,我们来一起看看:
public static void main( String[] args ) { Dog aDog = new Dog("Max"); // we pass the object to foo foo(aDog); // aDog variable is still pointing to the "Max" dog when foo(...) returns aDog.getName().equals("Max"); // true, java passes by value aDog.getName().equals("Fifi"); // false } public static void foo(Dog d) { d.getName().equals("Max"); // true // change d inside of foo() to point to a new Dog instance "Fifi" d = new Dog("Fifi"); d.getName().equals("Fifi"); // true }在这个例子里,aDog.getName()将会仍旧返回"Max".
在main里的aDog没有被foo()函数改变。要是是call-by-reference的话,我们应该能够预见,在调用foo()后,aDog.getName()应该返回Fifi。而实际上,并没有。
同样地:
public static void main( String[] args ) { Dog aDog = new Dog("Max"); foo(aDog); // when foo(...) returns, the name of the dog has been changed to "Fifi" aDog.getName().equals("Fifi"); // true } public static void foo(Dog d) { d.getName().equals("Max"); // true // this changes the name of d to be "Fifi" d.setName("Fifi"); }在上面的例子中,Fifi就是在调用foo()后,狗的名字了。因为对象的名字被设置成了Fifi。
再举出最后一个例子:
public void test() { MyClass obj = null; init(obj); //After calling init method, obj still points to null //this is because obj is passed as value and not as reference. //在调用init方法后,obj仍旧指向空 //这是因为,obj是值传递,而不是引用传递。 } private void init(MyClass objVar) { objVar = new MyClass(); }最后一句话:
In Java only references are passed and are passed by value
java中只有引用被传递了,而且是以值传递的方式
我回头看自己的文章都不知道写的啥意思,所以我又做了一次检验。我把结论说明白
你传进去函数的值(比如a)只是一个寻址的钩子,钩子的指向(也就是这个值)可以改变(比如改变成b,c,d…),当你在子函数中玩完,退出了,你钩子指向的变更,都是无效的。
外层函数继续它的一切时,会发现钩子的a值 曾经 被传递到子函数中,但是无论子函数对这个值(a)怎么变更(比如:a=b),回到主函数我这里 ,a还是a
当子函数内,令这个引用去指向新的内存了(by new 关键字),那么我们现在对同名的那个原来的引用,其实已经是指向新的内存地址(对应着一个新的对象),我们现在对引用的任何操作,都无法影响原来的那个引用了。 当子函数内,直接调用这个原引用的一些内置行为,改变了其属性,那么现在是确实地改变了其属性。
Java 是传递的引用,一个引用: 你可以理解为一个内存地址,一个容器,装着对象的实例,每个容器都有个名字,也就是我们声明变量时,给变量的那个名字。
那么,1》如果我们不赋新的(内存,引用)值,那么一切都好好的, 我们改了对象的什么,就真的改了,2》如果有新的值赋值给原引用,那么其实是子函数局部的这个容器装了一个新的内存地址,aka 新的引用,而对新的容器的任何变更,将不会影响到原容器。