搜索
您的当前位置:首页正文

常量池。

来源:步旅网

        紧接着主次版本号(0016)之后的是常量池入口,常量池可以理解为Class文件之中的资源仓库,他是Class文件结构中与其他项目关联最多的数据类型,也是占用Class文件空间最大的数据项目之一,同时他还是在Class文件中第一个出现的表类型数据项目。

        常量池中主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References)。字面量比较接近于Java语言层面的常量概念,如文本字符串、声明为final的常量值等。而符号引用则属于编译原理方面的概念,包括了下面三类常量:

  • 类和接口的全限定名(Fully Qualified Name)
  • 字段的名称和描述符(Descriptor)
  • 方法的名称和描述符

        常量池中每一项常量都是一个表,在JDK 1.7之前共有11种结构各不相同的表结构数据,在JDK 1.7中为了更好的支持动态语言调用,又额外增加了3种(CONSTANT_MethodHandle_inof、CONSTANT_MethodType_info和CONSTANT_InvokeDynamic_info)。

        这14种表都有一个共同的特点,就是表开始的第一位是一个u1类型的标志位(tag,取值间下表中标志列),代表当前这个常量属于哪种常量类型。这14种常量类型所代表的具体含义见下表。

类型标志描述
CONSTANT_Utf8_info1UTF-8编码的字符串
CONSTANT_Integer_info3整型字面量
CONSTANT_Float_info4浮点型字面量
CONSTANT_Long_info5长整型字面量
CONSTANT_Double_info6双精度浮点型字面量
CONSTANT_Class_info7类或接口的符号引用
CONSTANT_String_info8字符串类型字面量
CONSTANT_Fieldref_info9字段的符号引用
CONSTANT_Methodref_info10类中方法的符号引用
CONSTANT_InterfaceMethodref_info11接口中方法的符号引用
CONSTANT_NameAndType_info12字段或方法的部分符号引用
CONSTANT_MethodHandle_info15表示方法句柄
CONSTANT_MethodType_info16标识方法类型
CONSTANT_InvokeDynamic_info18表示一个动态方法调用点

类型名称数量
u1tag1
u2name_index1

类型名称数量
u1tag1
u2length1
u1byteslength

        length值说明了这个UTF-8编码的字符串长度是多少字节,他后面紧跟着的长度为length字节的连续数据是一个使用UTF-8缩略编码表示的字符串。UTF-8缩略编码与普通UTF-8编码的区别是:从'\u0001'到'\u007f'之间的字符(相当于1~127的ASCII码)的缩略编码使用一个字节表示,从'\u0080'到'\u07ff'之间的所有字符的缩略编码用两个字节表示,从'\u0800'到'\uffff'之间的所有字符的缩略编码就按照普通UTF-8编码规则使用三个字节表示。

        由于Class文件中方法、字段等都需要引用CONSTANT_Utf8_info型常量来描述名称,所以CONSTANT_Utf8_info型常量的最大长度也就是Java中方法、字段名的最大长度。而这里的最大长度就是length的最大值,即u2类型能表达的最大值65535。所以Java程序中如果定义了超过64KB英文字符的变量或方法名,将会无法编译。

       从上面代码中可以看出,计算机已经帮我们把整个常量池都计算了出来,并且第1、2项常量的计算结果与我们手工计算的结果一致。仔细看一下会发现,其中一些常量似乎从来没有在代码中出现过,如“I”、“V”、“<int>”、“LineNumberTable”、“LocalVariableTable”等,这些看起来在代码任何一处都没有出现过的常量是哪里来的呢?

        这部分自动生成的常量的确没有在Java代码里面直接出现过,但他们会被字段表(field_info)、方法表(method_info)、属性表(attribute_info)引用到,他们会用来描述一些不方便使用“固定字节”进行表述的内容。譬如描述方法的返回值是什么?有几个参数?每个参数的类型是什么?因为Java中的“类”是无穷无尽的,无法通过简单地无符号字节来描述一个方法用到了什么类,因此在描述方法的这些信息时,需要引用常量表中的符号引用进行表达。最后,将14种常量项的结构定义总结为下表以供参考。

常量项目类型描述
CONSTANT_Utf8_infotag
length
bytes
u1
u2
u1
值为1
UTF-8编码的字符串占用的字节数
长度为length的UTF-8编码的字符串
CONSTANT_Integer_infotag
bytes
u1
u4
值为3
按照高位在前存储的int值
CONSTANT_Float_infotag
bytes
u1
u4
值为4
按照高位在前存储的float值
CONSTANT_Long_infotag
bytes
u1
u8
值为5
按照高位在前存储的long值
CONSTANT_Double_infotag
bytes
u1
u8
值为6
按照高位在前存储的double值
CONSTANT_Class_infotag
index
u1
u2
值为7
指向全限定名常量项的索引
CONSTANT_String_infotag
index
u1
u2
值为8
指向字符串字面量的索引
CONSTANT_Fieldref_infotag
index
index
u1
u2
u2
值为9
指向声明字段的类或者接口描述符CONSTANT_Class_info的索引项
指向名称及类型描述符CONSTANT_NameAndType的索引项
CONSTANT_Methodref_infotag
index
index
u1
u2
u2
值为10
指向声明方法的类描述符CONSTANT_CLass_info的索引项
指向名称及类型描述符CONSTANT_NameAndType的索引项
CONSTANT_InterfaceMethodref_infotag
index
index
u1
u2
u2
值为11
指向声明方法的接口描述符CONSTANT_Class_info的索引项
指向名称及类型描述符CONSTANT_NameAndType的索引项
CONSTANT_NameAndType_infotag
index
index
u1
u2
u2
值为12
指向该字段或方法名称常量项的索引
指向该字段或方法描述符常量项的索引
CONSTANT_MethodHandle_infotag
reference_kind
reference_index
u1
u1
u2
值为15
值必须在·~9之间(包括1和9),他决定了方法句柄的类型。方法句柄类型的值表示方法句柄的字节码行为
值必须是对常量池有效索引
CONSTANT_MethodType_infotag
descriptor_index
u1
u2
值为16
值必须是对常量池的有效索引,常量池在该索引处的项必须是CONSTANT_Utf8_info结构,表示方法的描述符
CONSTANT_InvokeDynamic_infotag
bootstrap_method_attr_index
name_and_type_index
u1
u2
u2
值为18
值必须是对当前Class文件中引导方法表的bootstrap_methods[]数组的有效索引
值必须是对当前常量池的有效索引,常量池在该索引处的项必须是CONSTANT_NameAndType_info结构,表示方法名和方法描述符

因篇幅问题不能全部显示,请点此查看更多更全内容

Top