Java-对象状态在方法调用后不会更改

Java-对象状态在方法调用后不会更改,java,pass-by-reference,pass-by-value,Java,Pass By Reference,Pass By Value,初学者java问题,但我无法理解在下面的示例中按值调用(或引用)是如何工作的- 为什么当我的自定义字符串对象为时,字符串值在退出方法后不被修改?与Date等其他类相同 public class StringMadness { public static void main(String[] args) { String s = "Native String"; CustomStringObject cs = new CustomStringObject(); Syste

初学者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";
}

t
将指向新对象,并且范围仅限于方法,因此外部不可见更改


第二种情况是,您正在更改的值将更新为object,因此这些更改在方法调用后可见。

这两种方法之间有一个重要的区别:使用
hello(String)
您试图更改对
字符串的引用,使用
hello(CustomObject)
,给定一个引用,您正在使用引用更改对象的成员

hello(String)
引用
String
。在函数中,您试图更改引用指向的对象,但只更改引用的传递值副本。因此,您的更改不会反映在方法之外

hello(CustomObject)
将获得一个对象引用的副本,您可以使用该副本更改实际对象。将此视为更改对象的内容。因此,您的更改将反映在调用方中


给定对对象的引用,您可以使用其公开的方法/字段更改对象

比较这两种方法:

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
-这两个变量指的是同一个对象,因此,使用哪个变量访问它并不重要。

因为对于字符串,您只是在更改本地参数引用。

不起作用,因为字符串是不可变对象。

这并不是因为字符串是不可变的。即使这是一个StringBuilder,为参数指定一个新值也不会影响调用者…@JonSkeet:Agree。更新了我的答案。啊。。我看到了。谢谢最初,我的
hello(CustomStringObject o)
正在实例化一个新实例,如
o=new CustomStringObject()
中所示,我注意到在hello方法之外,实例化从未产生任何效果。“这就是引发这个问题的原因。”乔恩解释得很好。Foo示例很有帮助+1如果调用者传递空引用,则我观察到调用者的修改不会反映到调用者。为什么会这样?@feelgoodandprogramming:原因与您更改参数本身完全相同,调用者看不到这一点。引用是通过值传递的…这如何处理像布尔这样的“基本”对象?如果我将一个方法传递给这个对象,然后在方法外部设置它,那么这个方法外部的设置现在在方法内部适用吗?另外,请注意字符串是不可变的。当您调用hello(字符串)时,会传递字符串地址的副本(例如:0xABC4)。在该函数中,当您将新值分配给字符串时,这将为该字符串(例如:0xABC5)生成一个新地址,该地址在您的函数之外看不到。