JVM如何重用interned String子字符串?

时间:2016-07-15 11:42:02

标签: java string specifications effective-java

我知道你是否

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

在所有迭代中只创建一个String实例,而不像String s = new String("hi there");那样将在每次迭代中创建一个新实例。

但是,阅读约书亚布洛赫的有效Java:第2章第5项(第20页),它指出:

  

此外,保证对象将是   在同一个虚拟机中运行的任何其他代码重复使用包含相同的字符串文字[JLS, 3.10.5]

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

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

给出这个片段:

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

创建了多少个实例?

  • 3个实例(因此,短语并不完全准确)。
  • 2个实例s1s2(然后重新使用s3s1参考创建s2

3 个答案:

答案 0 :(得分:17)

JLS不保证任何子字符串的重用。这里的“包含”只是意味着在某处提到完全相同的字符串文字。 在“substring of”意义中使用。

答案 1 :(得分:3)

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

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

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

答案 2 :(得分:2)

如果s3重用s1s2个实例,则s3不会在物理上表示为连续字符数组,而是复合String } String个对象。

现在想象一下,在这样一个字符串中访问单个字符的性能影响 - 基于索引的访问实际上涉及将索引值与第一个字符串的大小进行比较,然后计算将成为第二个字符串索引的偏移量等。

实际上,相反的情况可能有意义:只能为"hi there"s3)分配一个基础字符序列,而s1s2只能存储它们的长度和该字符串中第一个字符的地址。但是我认为,对于jvm而言,确定“可嵌入的”是一项复杂而昂贵的工作。候选人和成本将超过潜在的利益。