运行时常量池 - 由运行时创建的变量填充?

时间:2017-03-27 13:31:01

标签: java jvm pool string-pool

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

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

例如:

Integer i = new Integer(127);

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

Integer i = Integer.valueOf(127);

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

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

第二个问题:我在很多文章中都找到了这句话:"每个班级都得到了运行时常数池#34;但这是什么意思?是否有一个RCP,它包含(例如)Integer类型的所有应用程序对象,或者每个类都有一个RCP,它包含在此类中出现的所有常量对象? (例如:Person,got age = Integer(18),isAdult = Boolean(true))。

2 个答案:

答案 0 :(得分:2)

首先,没有

的转换
Integer i = new Integer(127);

Integer i = Integer.valueOf(127);

这些结构完全不同。 new Integer(127)保证在每次评估时生成一个新实例,而Integer.valueOf(127)保证在每次评估时生成相同的实例,因为Integer.valueOf保证{{1}中的所有值}} 范围。这由-128 … +127的实现处理,并且与任何方式的常量池无关。当然,它是特定于实现的,但OpenJDK实现仅通过filling an array with references to these 256 instance the first time, this cache is accessed处理它。

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

这会影响由类的常量池引用的类,成员,Integer.valueOf(int)MethodTypeMethodHandle实例,但不会影响String或{{}等包装类型1}},因为常量池中没有这样的条目。池中的整数值是原始值,并且根本不存在布尔值。

不得将此与全局Integer池混淆,以引用文字的所有Boolean个实例以及intern()次调用的结果。

答案 1 :(得分:1)

问题1 - Anwser:否

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

首先,您从new Integer(127)Integer.valueOf(127)的翻译完全不正确,如post所述。如果您执行某些运行时验证,例如System.out.println(Integer.valueOf(127) == new Integer(127));(打印false),您将很快得出结论,无论您正在构建什么对象,使用new运算符始终创建一个新的,未缓存的对象。 (甚至String,实际上在运行时常量表中,需要被实习以获得对规范表的引用。)

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

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

RCPs全部存储在method area中。我个人不知道如何实现JVM,但JVMS有stated

  

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

尽管如此,只要您不打算在Oracle中申请工作,即使从性能调优视图也无关紧要。