String.intern和JVM有什么关系吗运行-Time Constant pool

Does String.intern has anything to to with JVM Run-Time Constant pool

根据jvms11,运行-时间常量池中有两种条目:符号引用,稍后可能会解析,以及静态常量,不需要进一步处理. 运行-时间常量池中的静态常量也是根据每个条目的结构从constant_pooltable中的条目派生而来。

我的理解是String.intern和JVM运行-Time Constant pool没有任何关系,但是中国最伟大的程序员之一说String.intern“在他的畅销书中 运行time 期间在 运行-Time Constant 池中放入一些东西。我们争论了很久,都无法说服对方

所以我的问题是,String.intern 与 JVM 运行-Time Constant pool 有什么关系吗?

这里是关于Rum-Time Constant pool

的jvms5.1

JVMS §5.1

The Java Virtual Machine maintains a run-time constant pool for each class and interface (§2.5.5).

术语“for each”的意思是没有一个运行时间常量池,但每个class或接口都有自己的专用池。后面几句更明确了这个数据结构对应的是一个class文件的常量池

The constant_pool table in the binary representation of a class or interface (§4.4) is used to construct the run-time constant pool upon class or interface creation (§5.3).

应该清楚的是,这个 per-class 结构与用于在整个 运行 时间规范化字符串实例的单一全局数据结构不同。

但是由于 class 文件中字符串常量的所有使用都表示为 class 文件常量池的索引,然后用于构造 class 的 运行-时间常量池,这些使用和全局数据结构有关系。如前所述 within §5.1

The static constants in the run-time constant pool are also derived from entries in the constant_pool table in accordance with the structure of each entry:

  • A string constant is a reference to an instance of class String, and is derived from a CONSTANT_String_info structure (§4.4.3). To derive a string constant, the Java Virtual Machine examines the sequence of code points given by the CONSTANT_String_info structure:
    • If the method String.intern has previously been invoked on an instance of class String containing a sequence of Unicode code points identical to that given by the CONSTANT_String_info structure, then the string constant is a reference to that same instance of class String.
    • Otherwise, a new instance of class String is created containing the sequence of Unicode code points given by the CONSTANT_String_info structure. The string constant is a reference to the new instance. Finally, the method String.intern is invoked on the new instance.

正式来说,对应于 class 中使用的字符串常量的 String 实例是 class 的 运行 时间常量池的一部分,但在中初始化String.intern 的条款以确保每个 class 在其池中都有规范化的字符串实例。

但这种关系只有一个方向。当应用程序代码显式调用 String.intern() 时,它不会访问 class 的 运行 时间常量池。甚至不清楚我们应该访问哪个 运行 时间常量池。

所以intern()与运行时间常量池无关,至少与其他调用者无关。

一个混乱的来源是 JVM 用来实现 intern() 的数据结构在 JVMS 或 JLS 中根本没有名称。所以,没有正式的名字,不同的媒体就会出现不同的名字。例如,API documentation of intern() 表示

A pool of strings, initially empty, is maintained privately by the class String.

它通常是某种哈希 table,但术语“池”符合其用途,并且由于它存在于 运行 时间,所以人们想出容易混淆的术语也就不足为奇了使用 JVMS §5.1 的 运行-时间常量池。

因此,在开始与其他开发人员进行激烈讨论之前,重要的是要弄清楚,是否每个人都在谈论同一个池。


作为附录,我在上面说过 String 正式 运行-time 常量池的一部分,因为这涉及实现的特定方面.

原则上,JVM 可以在创建池时使用 String 个实例初始化 class 的 运行 时间常量池的所有字符串条目。但正如 所证明的那样,广泛使用的 HotSpot JVM 并非如此,它在首次使用时查找或创建 String 实例,而不是 class 初始化时间。

这意味着 运行 时间常量池包含某种形式的原始字符数据,而不是对 String 实例的引用。 String一旦构造完成,就会被代码引用和重用,但是运行-时间常量池是修改为现在引用String还是字节码指令(ldc) 保留它,无法从 Java 应用程序中观察到。我们只能观察到,只要 class 存在,String 实例就不会被垃圾回收。