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是一个不可变对象