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 - 方法调用后对象状态不会改变[重复]的主要内容,如果未能解决你的问题,请参考以下文章

java布尔值在被调用方法中没有改变[重复]

线程各个状态

Java sleep()和wait()的区别

java中方法的参数传递机制(值传递还是引用传递)

当一个对象被当作参数传递到一个方法后,此方法可改变 这个对象的属性,并可返回变化后的结果,那么这里到底是值传 递还是引用传递?

当一个对象被当作参数传递到一个方法后,此方法可改变 这个对象的属性,并可返回变化后的结果,那么这里到底是值传 递还是引用传递?