8.1.8 解析CONSTANT_String_info入口
要解析类型是CONSTANT_String_info入口的人口,Java虚拟机必须把一个指向内部字符串对象 的引用放置到要被解析的常量池人口数据中去。该字符串对象(java.lang.String类的实例)必须 按照 string_index 项在 CONSTANT_String_info 中指明的 CONSTANT_Utf8_info入口所指定的字符顺序组织。
每一个Java虚拟机必须维护一张内部列表,它列出了所有在运行程序的过程中已被“拘留 (intern)”的字符串对象的引用。基本上,如果一个字符串在虚拟机的拘留列表上出现,就说它 是被拘留的。维护这个列表的关键是任何特定的字符序列在这个列表上只出现一次。
要拘留CONSTANT_String_info入口所代表的字符序列,虚拟机要检查内部拘留名单上这个 字符序列是否已经在编了。如果已经在编,虚拟机使用指向以前拘留的字符串对象的引用。否 则,虚拟机按照这个字符序列创建一个新的字符串对象,并把这个对象的引用编人列表。要完成CONSTANT_String_info人口的解析过程,虚拟机应把指向被拘留的字符串对象的引用放置到被解析的常量表人口数据中去。
在Java程序中,可以调用String类的intern ( )方法来拘留一个字符串。所有字面上表达的字符串都在解析CONSTANT_String_info入口的过程中被拘留了。如果具有相同序列的Unicode字 符串已经被拘留过,intern ()方法返回一个指向相符的巳经被拘留的字符串对象的应用。如果 字符串对象的intern ()方法被调用(该字符串对象包含的字符序列还没有被拘留过),那么这 个对象本身就被拘留。对象的intern ()在被调用的时候将返回指向同一个字符串对象的引用。 这里有个例子:
// On CD-ROM in file linking/ex1/Example1.java
class Example1 {
// Assume this application is invoked with one command-line
// argument, the string "Hi!".
public static void main(String[] args) {
// argZero, because it is assigned a String from the command
// line, does not reference a string literal. This string
// is not interned.
String argZero = args[0];
// literalString, however, does reference a string literal.
// It will be assigned a reference to a String with the value
// "Hi!" by an instruction that references a
// CONSTANT_String_info entry in the constant pool. The
// "Hi!" string will be interned by this process.
String literalString = "Hi!";
// At this point, there are two String objects on the heap
// that have the value "Hi!". The one from arg[0], which
// isn't interned, and the one from the literal, which
// is interned.
System.out.print("Before interning argZero: ");
if (argZero == literalString) {
System.out.println("they're the same string object!");
}
else {
System.out.println("they're different string objects.");
}
// argZero.intern() returns the reference to the literal
// string "Hi!" that is already interned. Now both argZero
// and literalString have the same value. The non-interned
// version of "Hi!" is now available for garbage collection.
argZero = argZero.intern();
System.out.print("After interning argZero: ");
if (argZero == literalString) {
System.out.println("they're the same string object!");
}
else {
System.out.println("they're different string objects.");
}
}
}
把宇符串“Hi!"作为第一个命令行参数执行时,示例程序Example]输出下列结果:
Before interning argzero: they're different string objects.
After interning argzero: they're the same string object.
8.1.9解析其他类型的入口
CONSTANT_Integer_info、CONSTANT_Long_info、CONSTANT_Float_info和 C0NSTANT_Double_info入口本身包含它们所表示的常量值,它们可以直接被解析。要解析这 类入口,很多虚拟机的实现什么都不需要做,直接使用那些值就行了。然而还有一些实现可能需要做一些处理。比如,在“小数在前”的计算机上运行的虚拟机可能选择在解析时交换值的 字节顺序。
CONSTANT_Utf8_info 和 CONSTANT_Name_AndType_info类型的人 口 永远不会被指令直接 引用。它们只有通过其他人口类型才能被引用,并且在那些引用人口被解析时才被解析。