JVM 如何重用滞留的字符串子字符串?

我知道如果你做

for (condition) {
    String s = "hi there";
}

在所有迭代中只创建一个实例,这与每次迭代中创建新实例不同。StringString s = new String("hi there");

但是,阅读Joshua Bloch的《Effective Java: Chapter 2 Item 5》(第20页),它指出:

此外,可以保证该对象将被在同一虚拟机中运行的任何其他代码重用,这些代码恰好包含相同的字符串文本 [JLS, 3.10.5]

AFAIK没有说碰巧相同的字符串文字,它说包含

阅读[JLS,3.10.5]找不到任何确切的参考,我对此有疑问。

给出这个片段:

String s1 = "hi ";
String s2 = "there";
String s3 = "hi there";

创建了多少个实例?

  • 3个实例(因此,短语并不真正精确)。
  • 2 个实例,并且(然后创建重用和引用)s1s2s3s1s2

答案 1

JLS 不保证子字符串的任何重用。这里的“contain”只是意味着该在某个地方提到了完全相同的字符串文本。它不是在“子字符串”意义上使用的。


答案 2

每个类文件都包含该类中使用的所有字符串文本或其他常量的列表(嵌入在指令流中的小数字常量除外)。如果列表中的项 19 是字符串文本 ,并且局部变量的索引为 6,则 生成的字节码可能是 /。"Freddy"FredFred="Freddy";ldc 19astore 6

当加载一个类时,系统将构建一个包含所有常量的表,对于引用类型的常量,将生成由此标识的对象。如果已知不存在字符串文本的实例,系统将向实习表添加一个实例并存储对该实例的引用。在生成机器代码时,将替换为加载相应引用的指令。ldc 19

重要的是,当类中的任何代码运行时,已经为其中的所有字符串文本创建了对象,因此类似语句将仅存储对包含 的已存在对象的引用,而不是创建新对象。Fred="Freddy";StringFreddyString