Java如何实现字符串池?

11

我想更深入地了解字符串池。请帮我找到Java中包含此实现的源类文件。

这个问题更多是与查找String Pool的源代码或实现相关,以便深入探究这个概念,了解其中一些未知或难以捉摸的事物。这样我们就可以更有效地使用字符串,或者考虑其他方法来实现自己的垃圾回收,以防我们的应用程序创建太多字面量和字符串对象。


通过查看实际代码,您不会更好地理解字符串池。基本上,它是一种哈希映射。具体来说,JVM 知道这个特殊的映射仍然支持包含的字符串的垃圾回收。如果您理解了这些原则,就没有必要查看代码。另一方面,如果您不理解,代码也无法帮助您。 - Holger
@Holger 好的。我知道 hashmap 的工作原理。我想了解一些实际实现过程中我尚未注意到的“非读取”事项。 - Ankit_ceo2
2个回答

20
抱歉让您失望,Java字符串池不是一个实际的Java类,而是在JVM中实现的,即它是用C++代码编写的。如果您查看 String类的源代码(几乎到底部),您会发现intern()方法是本地方法。您需要查看一些JVM代码以获取更多信息。
编辑:一些实现可以在这里找到(C ++头文件, C ++实现)。搜索StringTable
编辑2:正如Holger在评论中指出的那样,这不是JVM实现的硬性要求。因此,有可能有一种实现字符串池不同的JVM,例如使用实际的Java类。尽管我知道的所有常用JVM都是在JVM的C++代码中实现它的。

1
@Ankit_ceo2 我更新了我的答案,并提供了一些可以找到它的信息。 - MartinS
1
好的,有用Java编写的JVM。然而,字符串池是HotSpot的私有内部优化细节,因此其他JVM可能没有它。 - Jörg W Mittag
2
@Jörg W Mittag:相同的字符串字面量由相同的实例表示,当在相等的实例上调用String.intern()时,也返回相同的实例,这是规范要求的。因此,每个JVM都必须有某种字符串池或等效物。只有它实际工作的方式是依赖于实现的。 - Holger
1
这也反映在JVM规范中§5.1.运行时常量池:“Java编程语言要求相同的字符串字面值(即包含相同代码点序列的字面值)必须引用String类的同一实例(JLS §3.10.5)。此外,如果在任何字符串上调用String.intern方法,则结果是对与该字符串作为字面值出现时返回的同一类实例的引用 - Holger
1
@Jörg W Mittag:这段Java代码处理的是特定类文件中的字符串常量,而不是JVM实现的全局池。类的常量池与JVM的全局字符串池交互,但它们仍然是不同的池。此外,这个答案提到了Oracle著名的参考JVM,但并不一定适用于世界上所有的JVM。 - Holger
显示剩余9条评论

6
您可以阅读这篇文章:直译字符串 当一个.java文件编译成一个.class文件时,所有的字符串字面量都会被特殊标注,就像所有的常量一样。当一个类被加载(请注意,在初始化之前发生加载),JVM会遍历该类的代码并查找字符串字面量。当它找到一个时,它会检查堆中是否已经引用了等效的字符串。如果没有,它会在堆上创建一个字符串实例,并将对该对象的引用存储在常量表中。一旦对该字符串对象的引用被建立,程序中对该字符串字面量的任何引用都将被简单地替换为从字符串字面量池中引用的对象的引用。
因此,在上面的示例中,字符串字面量池中只有一个条目,它将引用包含单词“someString”的字符串对象。本地变量one和two都将被分配对该单个字符串对象的引用。您可以通过查看上面程序的输出来证明这一点。虽然equals()方法检查字符串对象是否包含相同的数据(“someString”),但当用于对象时,==运算符检查引用相等性——也就是说,只有两个引用变量引用完全相同的对象时才返回true。在这种情况下,引用相等。从上面的输出可以看出,本地变量one和two不仅引用包含相同数据的字符串,而且引用同一个对象。

非常糟糕的引用:存在许多错误,并且实现随时间改变。例如,大部分工作由编译器完成,而不是JVM,JVM检查.class文件中的常量表,而不是字节码。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接