3

在 Java 中有很多关于字符串不变性的问题,问题的作者实际上重新分配了参考。

然而,有一个值得注意的情况,似乎没有重新分配字符串:

String s = "hello";
s += " world";

您将其视为对字符串的实际修改。在家里试试。

我很确定这是某种语法糖,并被编译器翻译成具有与以下相同语义的东西:

String s = "hello";
s = s + " world";

有人可以证实这个事实吗?

4

4 回答 4

5

错误的。

x += y只是x = x + y.
它仍然是一个常规的赋值操作,它不会修改任何现有的实例。

于 2012-12-10T20:29:23.010 回答
4

它是一个新对象,原始对象不会被修改;

这个:

public static void main(String[] args) {

    String s = "hello";
    s += " world";
    System.out.println(s);

}

翻译成这样:

public static void main(java.lang.String[]);
    Code:
        0: ldc           #2                  // String hello
        2: astore_1
        3: new           #3                  // class java/lang/StringBuilder
        6: dup
        7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
        10: aload_1
        11: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        14: ldc           #6                  // String  world
        16: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        22: astore_1
        23: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        26: aload_1
        27: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        30: return
}

这会创建两个Strings 并将它们添加到一个新String对象中。

于 2012-12-10T20:47:00.613 回答
4

我既不能确认也不能否认。如果优化编译器可以向自己证明没有其他线程可以“看到” +=s 的初始(pre-)值,那么它将可以自由地优化连接并将代码编译为等价于

String s = "hello world";

编译器对于它们如何从源代码转换为字节码有很大的自由度,只要它们遵循内存模型。

于 2012-12-10T20:36:07.860 回答
0

为无法阅读 Java 字节码的人扩展 skynorth 的答案,给出以下源代码:

public static void main(String... args) {
    String s = "hello";
    s += "world";
}

在编译的类文件上运行JAD 反编译器时,您会得到以下 Java 代码:

public static void main(String args[]) {
    String s = "hello";
    s = (new StringBuilder(String.valueOf(s))).append("world").toString();
}

这是不言自明的,并且与 skynort 发布的字节码完全对应。

于 2012-12-10T20:59:38.800 回答