Java是否真的按值传递对象?
可能重复: Java是否通过引用传递?
public class myClass{ public static void main(String[] args){ myObject obj = new myObject("myName"); changeName(obj); System.out.print(obj.getName()); // This prints "anotherName" } public static void changeName(myObject obj){ obj.setName("anotherName"); } }
我知道Java通过值传递,但为什么它在前面的例子中通过引用传递obj
并更改它?
Java总是按值传递参数,而不是通过引用传递参数。 在您的示例中,您仍然通过其值传递obj
,而不是引用本身。 在方法changeName
,您将另一个(本地)引用obj
分配给您作为参数传递的同一对象。 修改该引用后,您将修改原始引用obj
,该引用将作为参数传递。
编辑:
让我通过一个例子解释一下:
public class Main { public static void main(String[] args) { Foo f = new Foo("f"); changeReference(f); // It won't change the reference! modifyReference(f); // It will change the object that the reference refers to! } public static void changeReference(Foo a) { Foo b = new Foo("b"); a = b; } public static void modifyReference(Foo c) { c.setAttribute("c"); } }
我将逐步解释这个:
1-声明名为f
的Foo
类型的引用,并将其分配给类型为Foo
的新对象,其属性为"f"
。
Foo f = new Foo("f");
2-从方法方面,声明了名为a
的类型为Foo
的引用,并且它最初被赋值为null
。
public static void changeReference(Foo a)
3-当您调用方法changeReference
,引用a
将被分配给作为参数传递的对象。
changeReference(f);
4-声明名为b
的类型为Foo
的引用,并将其赋值给属性为"b"
Foo
类型的新对象。
Foo b = new Foo("b");
5- a = b
将引用a
NOT f
重新分配给其属性为"b"
的对象。
6-当您调用modifyReference(Foo c)
方法时,将创建引用c
并将其分配给具有属性"f"
的对象。
7- c.setAttribute("c");
将更改引用c
指向它的对象的属性,并且它是引用f
指向它的同一对象。
我希望你现在明白如何将对象作为参数传递在Java中:)
在Java中,对象句柄或对象的标识被视为值。 按值传递意味着传递此句柄,而不是对象的完整副本。
术语“通过引用传递”中的“引用”也不意味着“引用对象”。 它表示“引用变量” – 可以存储值的函数定义(或者更确切地说是调用帧)中的命名“存储桶”。
通过引用传递意味着被调用的方法可以在调用方法中更改变量值 。 (例如,在C标准库中,函数scanf
这种方式工作。)这在Java中是不可能的。 您始终可以更改对象的属性 – 它们不被视为其“值”的一部分。 它们是完全不同的独立物体。
你正在改变obj
的属性 ,而不是改变obj
(参数)本身。
关键在于,如果你将obj
指向changeName
中的其他changeName
,则该更改将不会反映在main
。
有关进一步说明,请参阅此post 。
它没有改变obj(你的代码也没有改变它)。 如果通过引用传递,你可以写:
public static void changeName(myObject obj){ obj = new myObject("anotherName"); }
并使用main方法打印“anotherName”。
Java正在传递您传递给函数的副本。 当它是基本类型时 – 它将是值的副本。 当它是一个对象时 – 你传递了参考副本。 在您的代码示例中,您正在修改其中一个对象属性,但不修改引用本身,因此名称将被更改。 但是,如果您想在changeName函数中将新对象分配给obj变量,那么您将更改引用,因此外部obj将具有旧值。
它将对obj的引用作为一个值传递(我知道有点令人困惑:))。
所以我们假设它复制了指向obj值的指针并传递了它。
这意味着你可以做以下事情:
public static void changeName(myObject obj){ obj.setName("anotherName"); obj = new myObject(); }
和声明
System.out.print(obj.getName());
仍然会引用旧对象(你做的setName)。