我不确定运行时常量池的某些属性。
运行时常量池,由常量池中的数据填充(来自.class文件,在类加载期间)。但它是否也被运行时创建的变量所填充?或者它们是否在编译期间转换为文字,并存储在常量池中?
例如:
Integer i = new Integer(127);
被视为文字,因为转换为:
Integer i = Integer.valueOf(127);
在编译期间,并存储在常量池中?
如果它没有那样工作,运行时常量池是否有任何运行时机制?
第二个问题:我在很多文章中都找到了这句话:"每个班级都得到了运行时常数池#34;但这是什么意思?是否有一个RCP,它包含(例如)Integer类型的所有应用程序对象,或者每个类都有一个RCP,它包含在此类中出现的所有常量对象? (例如:Person,got age = Integer(18),isAdult = Boolean(true))。
答案 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)
,MethodType
和MethodHandle
实例,但不会影响String
或{{}等包装类型1}},因为常量池中没有这样的条目。池中的整数值是原始值,并且根本不存在布尔值。
不得将此与全局Integer
池混淆,以引用文字的所有Boolean
个实例以及intern()
次调用的结果。
答案 1 :(得分:1)
Integeral包装器类型缓存,而不是存储在常量池中。它们只是堆中的普通对象。 Integer
或Byte
缓存是运行时优化,不是VM优化,也不是编译时优化。在调用构造函数创建新构造函数时,它们不会被缓存的神奇地替换。
首先,您从new Integer(127)
到Integer.valueOf(127)
的翻译完全不正确,如post所述。如果您执行某些运行时验证,例如System.out.println(Integer.valueOf(127) == new Integer(127));
(打印false
),您将很快得出结论,无论您正在构建什么对象,使用new
运算符始终创建一个新的,未缓存的对象。 (甚至String
,实际上在运行时常量表中,需要被实习以获得对规范表的引用。)
i
变量hold只是指向堆中Integer
对象的引用。如果您使用valueOf
,它将被缓存。反之亦然。
RCPs全部存储在method area中。我个人不知道如何实现JVM,但JVMS有stated:
Java虚拟机维护一个每类型常量池(第2.5.5节),这是一种运行时数据结构,它服务于传统编程语言实现的符号表的许多目的。
尽管如此,只要您不打算在Oracle中申请工作,即使从性能调优视图也无关紧要。