0

我不确定运行时常量池的某些属性。

运行时常量池,由常量池中的数据填充(来自 .class 文件,在类加载期间)。但它是否也被运行时创建的变量填充?还是在编译期间将它们转换为文字,并存储在常量池中?

例如:

Integer i = new Integer(127);

被视为文字,因为转换为:

Integer i = Integer.valueOf(127);

在编译期间,并存储在常量池中?

如果它不是那样工作,是否有运行时常量池的运行时机制?

第二个问题:我在很多文章中找到了这句话:“每个类都有Runtime constant pool”,但它是什么意思?是否有一个 RCP,包含(例如)整数类型的所有应用程序对象,或者每个类都有一个 RCP,包含该类中出现的所有常量对象?(例如:Person,得到年龄 = Integer(18),并且 isAdult = Boolean(true))。

4

2 回答 2

2

首先,没有转换

Integer i = new Integer(127);

Integer i = Integer.valueOf(127);

这些构造完全不同。new Integer(127)保证每次评估时都会产生一个新实例,而Integer.valueOf(127)保证每次评估时都会产生相同的实例,作为范围内Integer.valueOf所有值的保证-128 … +127。这是由实现处理的,Integer.valueOf(int)与常量池没有任何关系。当然,它是特定于实现的,但是 OpenJDK 实现通过简单地在数组中填充对这 256 个实例的引用来处理这个问题,第一次访问这个缓存

虽然每个类在其类文件中都有一个常量池是正确的,但说每个类都有一个运行时常量池(单独)可能会产生误导。这又是一个 JVM 实现细节。虽然可以将每个类常量池 1:1 映射到运行时常量池,但显然将生活在同一解析上下文(即由同一类加载器定义)中的类的常量池合并到一个池中是有意义的,所以不需要多次解析相同的常量。尽管从概念上讲,每个类都有其池的运行时表示,即使它们没有以这种幼稚的形式实现。所以“每个类都有一个运行时常量池”这句话没有错,但并不一定意味着每个类都会有这样的数据结构。

这会影响由类的常量池引用的类、成员和实例MethodType,但不会影响诸如or之类的包装器类型,因为常量池中没有此类条目。池中的整数值是原始值,布尔值根本不存在。MethodHandleStringIntegerBoolean

这不能与全局String池引用所有String文字实例和intern()调用结果相混淆。

于 2017-03-27T14:24:11.450 回答
1

问题 1 - 回答者:否

整数包装器类型被缓存,而不是存储在常量池中。它们只是堆中的普通对象。Integer或者Byte缓存是运行时优化,不是 VM 优化,也不是编译时优化。当它们的构造函数被调用来创建一个新的时,它们不会神奇地被缓存的替换。

首先,如本文所述,您从new Integer(127)toInteger.valueOf(127)翻译根本不正确。如果您进行一些运行时验证,例如(prints ),您将很快得出结论,无论您正在构造什么对象,使用运算符总是会创建一个新的、未缓存的对象。(Even s,实际上在运行时常量表中,需要被实习以获取对规范表的引用。)System.out.println(Integer.valueOf(127) == new Integer(127));falsenewString

什么i变量持有只是指向Integer堆中对象的引用。如果您正在使用它将被缓存valueOf,反之亦然。


问题 2 - Anwser:每个类都有一个 RCP,但它们都在同一个内存区域中

RCP都存储在方法中。我个人不知道 JVM 是如何实现的,但是 JVMS 已经声明

Java 虚拟机维护每个类型的常量池(第 2.5.5 节),这是一种运行时数据结构,可用于传统编程语言实现的符号表的许多目的。

不过,即使从性能调优的角度来看,这也无关紧要,只要您不打算申请 Oracle 的工作。

于 2017-03-27T14:21:43.187 回答