Java - 方法调用后对象状态不会改变[重复]
Posted
技术标签:
【中文标题】Java - 方法调用后对象状态不会改变[重复]【英文标题】:Java - Object state does not change after method call [duplicate] 【发布时间】:2012-08-01 20:18:53 【问题描述】:初学者 java 问题,但我无法理解在下面的示例中按值调用(或引用)是如何工作的 -
我的自定义字符串对象在退出方法后,为什么字符串值没有被修改。 ?与 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";
【问题讨论】:
【参考方案1】:比较这两种方法:
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 总是使用按值传递,但您需要记住,对于类,变量(或实际上任何其他表达式)的值是引用,而不是对象。你不需要使用参数传递来看到这个:
Foo foo1 = new Foo();
Foo foo2 = foo1;
foo1.someField = "changed";
System.out.println(foo2.someField) // "changed"
这里的第二行将foo1
的值复制到foo2
- 这两个变量引用同一个对象,因此您使用哪个变量来访问它并不重要。
【讨论】:
啊……我明白了。谢谢....最初,我的hello(CustomStringObject o )
正在实例化一个新实例,就像o = new CustomStringObject()
一样,我注意到在 hello 方法之外,实例化从未有任何效果。这就是引发问题的原因。
@Jon 很好的解释。 Foo 示例有帮助。 +1
如果调用者传递空引用,那么我观察到被调用者修改不会反映给调用者。为什么会这样?
@feelgoodandprogramming:出于与更改参数本身完全相同的原因,调用者不可见。引用按值传递...
如何处理像布尔这样的“原始”对象?如果我将这个对象传递给一个方法,然后将其设置在方法之外,那么该方法之外的设置现在是否适用于方法内部?【参考方案2】:
这两种方法之间有一个重要区别:使用hello(String)
,您尝试将reference更改为String
,而使用hello(CustomObject)
,给定一个参考,您使用引用更改对象的成员。
hello(String)
引用String
。在函数中,您尝试更改引用指向的对象,但您只是更改了引用的 pass-by-value 副本。因此,您的更改不会反映在方法之外。
hello(CustomObject)
获得一个对象引用的副本,然后您可以使用它来更改实际对象。将此视为更改对象的内容。因此,您的更改会反映在调用方中。
给定一个对象的引用,您可以使用它的公开方法/字段来更改对象
【讨论】:
另外,请注意字符串是不可变的。当您调用 hello(String) 时,会传递字符串地址的副本(例如:0xABC4)。在该函数中,当您为字符串分配新值时,这将为该字符串生成一个新地址(例如:0xABC5),该地址将不会在您的函数之外看到。【参考方案3】:因为对于字符串,您只是更改了本地参数引用。
【讨论】:
【参考方案4】:t
将指向新对象并仅限于方法,因此更改在外部不可见。
第二种情况,你改变的值会被更新为对象,所以这些改变在方法调用之后是可见的。
【讨论】:
这并不是因为字符串是不可变的。即使这是一个 StringBuilder,为参数分配一个新值也不会影响调用者... @JonSkeet:同意。更新了我的答案。【参考方案5】:不起作用,因为 String 是不可变对象
【讨论】:
以上是关于Java - 方法调用后对象状态不会改变[重复]的主要内容,如果未能解决你的问题,请参考以下文章
当一个对象被当作参数传递到一个方法后,此方法可改变 这个对象的属性,并可返回变化后的结果,那么这里到底是值传 递还是引用传递?
当一个对象被当作参数传递到一个方法后,此方法可改变 这个对象的属性,并可返回变化后的结果,那么这里到底是值传 递还是引用传递?