Java – 方法调用后对象状态不会改变
初学java问题,但我无法理解如下所示的示例中的call-by-Value(或Reference)是如何工作的 –
为什么在我的自定义String对象退出方法后,String值不会被修改。 ? 与Date等其他类相同
public class StringMadness { public static void main(String[] args) { String s = "Native String"; CustomStringObject cs = new CustomStringObject(); System.out.println("Custom String Before: " + cs.str); hello(cs); System.out.println("Custom String After: " + cs.str); System.out.println("Native String Before: " + s); hello(s); System.out.println("Native String After: " + s); } private static void hello(String t) { t = "hello " + t; } private static void hello(CustomStringObject o) { o.str = "hello " + o.str; } } class CustomStringObject { String str = "Custom String"; }
比较这两种方法:
private static void hello(String t) { t = "hello " + t; } private static void hello(CustomStringObject o) { o.str = "hello " + o.str; }
在第一种情况下,您要为t
分配一个新值。 这对调用代码没有影响 – 您只是更改参数的值,并且所有参数都在Java中通过值传递。
在第二种情况下,您要为o.str
分配一个新值。 这正在改变o
的值引用的对象内的字段的值。 调用者将看到该更改,因为调用者仍然具有对该对象的引用。
简而言之:Java总是使用pass by value,但您需要记住,对于类,变量(或实际上任何其他表达式)的值是引用,而不是对象。 您不需要使用参数传递来查看:
Foo foo1 = new Foo(); Foo foo2 = foo1; foo1.someField = "changed"; System.out.println(foo2.someField) // "changed"
这里的第二行将foo1
的值复制到foo2
– 两个变量引用同一个对象,因此使用哪个变量来访问它并不重要。
这两种方法之间有一个重要的区别:使用hello(String)
你试图改变对String
的引用 ,并且使用hello(CustomObject)
,给定引用,你使用引用来改变对象的成员。
hello(String)
接受hello(String)
的引用。 在函数中,您尝试更改引用所指向的对象,但您只是更改引用的按值传递副本 。 因此,您的更改不会反映在方法之外。
hello(CustomObject)
被赋予对象的引用的副本,然后您可以使用它来更改实际对象。 可以将此视为更改对象的内容 。 因此,您的更改将反映在调用方中。
给定对象的引用 ,您可以使用它的公开方法/字段更改对象
因为对于String,您只是更改本地参数引用。
t
将指向新对象并仅限于方法,因此更改在外部不可见。
第二种情况,您要更改的值将更新为object,因此在方法调用后可以看到这些更改。
不起作用,因为String是一个不可变对象