plenty questions {{3}}关于Java中的字符串不变性,问题的作者实际上重新分配了引用。
然而,有一个非常明显的案例,似乎没有重新分配字符串:String s = "hello";
s += " world";
您将其视为字符串的实际修改。在家尝试。
我很确定这是某种语法糖,并且被编译器翻译成具有相同语义的东西:
String s = "hello";
s = s + " world";
有人可以证实这个事实吗?
答案 0 :(得分:5)
错误。
x += y
只是x = x + y
的简写
它仍然是一个常规的赋值操作,它不会修改任何现有的实例。
答案 1 :(得分:4)
我既不能确认也不能否认。如果优化编译器可以向自己证明没有其他线程可以“看到”s的初始(pre - +=
)值,则可以自由地优化掉串联并将代码编译为等效的
String s = "hello world";
只要编译器遵循内存模型,编译器就可以完全自由地将它们从源代码转换为字节代码。
答案 2 :(得分: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
}
这会创建两个String
并将它们添加到新的String
对象中。
答案 3 :(得分:0)
为那些无法读取Java字节代码的人扩展skynorth的答案,给出以下源代码:
public static void main(String... args) {
String s = "hello";
s += "world";
}
在已编译的类文件上运行JAD decompiler时,您将获得以下Java代码:
public static void main(String args[]) {
String s = "hello";
s = (new StringBuilder(String.valueOf(s))).append("world").toString();
}
这是非常不言自明的,并且与skynort发布的字节码精确对应。