Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
字符串的Java不变性,带有+=&引用;操作人员_Java_String_Immutability - Fatal编程技术网

字符串的Java不变性,带有+=&引用;操作人员

字符串的Java不变性,带有+=&引用;操作人员,java,string,immutability,Java,String,Immutability,Java中存在关于字符串不变性的问题,问题的作者实际上为此重新分配了引用 然而,有一个引人注目的例子,似乎没有重新分配字符串: String s = "hello"; s += " world"; 您将其视为字符串的实际修改。在家里试试 我很确定这是一种语法糖,编译器会将其翻译成与以下相同的语义: String s = "hello"; s = s + " world"; 有人能证实这个事实吗?错了 x+=y只是x=x+y的缩写 它仍然是一个常规的赋值操作,并且不会修改任何现有实例。我既不能

Java中存在关于字符串不变性的问题,问题的作者实际上为此重新分配了引用

然而,有一个引人注目的例子,似乎没有重新分配字符串:

String s = "hello";
s += " world";
您将其视为字符串的实际修改。在家里试试

我很确定这是一种语法糖,编译器会将其翻译成与以下相同的语义:

String s = "hello";
s = s + " world";
有人能证实这个事实吗?

错了

x+=y
只是
x=x+y
的缩写

它仍然是一个常规的赋值操作,并且不会修改任何现有实例。

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

String s = "hello world";

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

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

这:

翻译成这样:

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
}
publicstaticvoidmain(java.lang.String[]);
代码:
0:ldc#2//字符串你好
2:astore_1
3:new#3//class java/lang/StringBuilder
6:dup
7:invokespecial#4//方法java/lang/StringBuilder。”“:()V
10:aload_1
11:invokevirtual#5//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14:ldc#6//字符串世界
16:invokevirtual#5//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19:invokevirtual#7//方法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//方法java/io/PrintStream.println:(Ljava/lang/String;)V
30:返回
}

这将创建两个
字符串
并将它们添加到一个新的
字符串
对象中。

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

public static void main(String... args) {
    String s = "hello";
    s += "world";
}
在编译的类文件上运行时,您会得到以下Java代码:

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

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

确认。在
+=
之后,堆中会有太多字符串,“hello”和“hello world”。前者没有参考,很快就会被垃圾回收。后者被引用,将一直存在到发布。在第二行,s是一个新对象。好吧,不是“错”。我想说“确认”:DIt最好包含一些来自StringBuilder.java的源代码,以强调事实上是一个新的字符串对象。(定义
toString()
)<代码>返回新字符串(值,0,计数)我不确定这是否正确<代码>“hello world”是一个常量字符串表达式,正如
“hello”+“world”
一样。但我不认为OP的代码片段算作一个。因此,如果您后来测试了
s==“hello world”
(故意使用==而不是equals),那么连接是否得到了优化就无关紧要了(对字符串进行内部处理)。我不确定的是,使用
+
sugar创建的常量字符串是否需要作为新对象,或者是否只允许作为新对象。
public static void main(String args[]) {
    String s = "hello";
    s = (new StringBuilder(String.valueOf(s))).append("world").toString();
}