字符串池行为

时间:2013-01-23 21:49:26

标签: java string pool

我读了这个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));

6 个答案:

答案 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

Java Language Specification州:

  

每个字符串文字都是一个参考   (§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)

请参阅String#intern()的文档。最后一行指出:

  

所有文字字符串和字符串值常量表达式都是   实习。

您的+=示例既不是文字字符串也不是字符串值常量表达式,因此它不会放在字符串池中。

答案 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的字面值是相同的,因此编译器将它们指向字符串池中的相同文字值

  1. 为 s1 + =“d”;
    s2 + =“d”;
  2. 编译器无法知道s1和s2是否最终会成为相同的值, 在运行时,除非调用String.intern(),否则jvm将不检查字符串文字池以查看该值是否已存在。