我读了这个Questions about Java's String pool 并了解字符串池的基本概念,但仍然不了解行为。
首先:如果您直接指定值并且s1和s2都引用池中的同一对象,则它可以工作
String s1 = "a" + "bc";
String s2 = "ab" + "c";
System.out.println("s1 == s2? " + (s1 == s2));
但是如果我改变字符串s1 + =“d”,那么池应该有一个字符串对象“abcd”?那么当我更改s2 + =“d”时,它应该在池中找到字符串对象“abcd”,并将对象分配给s2?但它没有,它们不会被引用到同一个对象。为什么会这样?
String s1 = "abc";
String s2 = "abc";
System.out.println("s1 == s2? " + (s1 == s2));
s1 += "d";
s2 += "d";
System.out.println("s1 == s2? " + (s1 == s2));
答案 0 :(得分:7)
当您在字符串上调用String.intern()
时,可以保证汇总字符串。
String s1 = "abcd".intern();
String s2 = "abc";
s2 += "d";
s2 = s2.intern();
s1 == s2 // returns true
当编译器看到常量时,它足够聪明,可以优化和汇集字符串文字,即:
String s1 = "abcd";
String s2 = "abcd";
s1 == s2 // returns true
每个字符串文字都是一个参考 (§4.3)实例(§4.3.1,§12.5) String类(第4.3.3节)。串 对象具有常量值。串 文字 - 或者更一般地说,字符串 这是常数的值 表达式(§15.28) - 实际上是“实习” 至于共享唯一的实例,使用 方法String.intern。
所以在s2 += "d"
的情况下,编译器并不像你那样聪明,只是汇集"d"
。
答案 1 :(得分:3)
我不确定这一点,所以这几乎是猜测,但我怀疑在第一个例子中可能会有一些编译器技巧(它是内联的,非常明显的是发生了什么),但它并不聪明足以在第二个例子(它不那么明显)中将它拉下来。
如果我是正确的,要么编译器看到"a" + "bc"
并且只是在编译时将其压缩到"abc"
,或者它看到两行并汇集字符串,因为它意识到它们将被使用。我打赌前者......
并非所有字符串都必须汇总。
答案 2 :(得分:2)
答案 3 :(得分:2)
编译器可以执行常量评估,但不能修改值
请尝试关注,看看如果从任一变量中删除final
会发生什么。
final String s1 = "abc";
final String s2 = "abc";
System.out.println("s1 == s2? " + (s1 == s2));
String s3 = s1 + "d";
String s4 = s2 + "d";
System.out.println("s3 == s4? " + (s3 == s4));
答案 4 :(得分:0)
这是我的猜测:
String s1 =“a”+“bc”; 字符串s2 =“ab”+“c”;
我认为这是编译时间,这些是确定生成相同的字符串,因此只为这两个字符串创建了一个对象。
但是当你向他们两个添加“d”时,这是为两个字符串单独完成的(因为它是在实时完成的,可能会有异常中断等等,所以它不能预先做到)所以它不会自动使它们引用一个对象。
答案 5 :(得分:0)
我认为这里发生的是: 为... String s1 =“a”+“bc”; 字符串s2 =“ab”+“c”; Java编译器很聪明,知道s1和s2的字面值是相同的,因此编译器将它们指向字符串池中的相同文字值
编译器无法知道s1和s2是否最终会成为相同的值, 在运行时,除非调用String.intern(),否则jvm将不检查字符串文字池以查看该值是否已存在。