- 我们已知的在Class文件里,常量池占的比重是非常大的,其它结构中或多或少的都要通过索引来常量池获取它们所需要的信息。但常量分为哪几种类型呢,常量又是如何存储的呢,这是我们本博客的所要讲解的内容
- 具体关于常量池的其它问题,请参考Class类文件结构 的常量池一节
- 常量表(cp_info)的类型主要分为两大类:字面量(Literal)和符号引用(Symbolic References);
- 常量表共有11种表结构,这些表的相同的部分以及区分的方法在于,它们表结构的第一位都是类型为u1称为“tag”的值,根据tag值的不同来区分究竟是属于什么结构的常量表;如下表是11种不同功能的常量表简单说明及tag值。
类型 | tag值 | 所属类别 | 类型描述 |
---|---|---|---|
CONSTANT_Utf8_info | 1 | 字面量 | UTF-8编码的字符串 |
CONSTANT_Integer_info | 3 | 字面量 | 整型字面量 |
CONSTANT_Float_info | 4 | 字面量 | 浮点型字面量 |
CONSTANT_Long_info | 5 | 字面量 | 长整型字面量 |
CONSTANT_Double_info | 6 | 字面量 | 双精度浮点型字面量 |
CONSTANT_Class_info | 7 | 符号引用 | 类或接口的符号引用 |
CONSTANT_String_info | 8 | 字面量 | 字符串类型字面量 |
CONSTANT_Fieldref_info | 9 | 符号引用 | 字段的符号引用 |
CONSTANT_Methodref_info | 10 | 符号引用 | 类中方法的符号引用 |
CONSTANT_InterfaceMethodref_info | 11 | 符号引用 | 接口中方法的符号引用 |
CONSTANT_NameAndType_info | 12 | 符号引用 | 字段或方法的部分符号引用 |
1.CONSTANT_Utf8_info
- 表结构:
类 型 | 项目 | 数 目 | 说明 |
---|---|---|---|
u1 | tag | 1 | 值为1 |
u2 | length | 1 | UTF-8缩略编码的字符串占用的字节数 |
u1 | bytes | length | UTF-8缩略编码的字符串的字节值 |
- 相比于其它常量表,该表比较特殊的地方在于,源文件中几乎所有可见的字符串都存放在CONSTANT_Utf8_info中, 其他类型的常量池项只不过是对CONSTANT_Utf8_info的引用,并附增上一些特有的属性,比如是符号引用。
- 这里有一个很有意思的地方是,这里使用的编码格式是 UTF-8缩略编码,很明显这是为了节省空间,但缩略编码与UTF-8编码的不同之在哪呢?从’\u0001’到’\u007f’之间的字符,缩略编码采用一个字节存储,从’\u0080’到’\u07ff’之间的字符采用两个字节存储,从’\u0800’到’\uffff’之间的字符按照普通的UTF-8编码格式三个字节来存储。
- 关于UTf-8缩略编码,我有一个问题没想明白,比如’\u0707’这个数据,读取的时候可以理解为一个两字节的字符’\u0707’,也可理解两个一字节的字符’\u0007’,’\u0007’。这是不是有其它辅助的解决办法,还是我哪里思考错误缺漏了?
2.CONSTANT_Integer_info
- 表结构:
类 型 | 项目 | 数 目 | 说明 |
---|---|---|---|
u1 | tag | 1 | 值为3 |
u4 | bytes | 1 | 整型常量值 |
- 不用多说了,就是存储四个字节长度的整型常量值
3.CONSTANT_Float_info
- 表结构:
类 型 | 项目 | 数 目 | 说明 |
---|---|---|---|
u1 | tag | 1 | 值为4 |
u4 | bytes | 1 | 单精度浮点型常量值 |
4.CONSTANT_Long_info
- 表结构:
类 型 | 项目 | 数 目 | 说明 |
---|---|---|---|
u1 | tag | 1 | 值为5 |
u4 | high_bytes | 1 | 长整型的高四位值 |
u4 | low_bytes | 1 | 长整型的低四位值 |
- 类文件结构中基本的长度最长也只有u4(四个字节),所以对于8个字节长的长整型来说,必须要拆成两个u4的类型来存储,下面的CONSTANT_Double_info类似。
- 长整型的高四位其实在低位,长整型的低四位其实在高位,但是我们连着8个字节读取的时候就是一个完整的long类型数据,所以这是基于这样读取方便设计的吗?
5.CONSTANT_Double_info
- 表结构:
类 型 | 项目 | 数 目 | 说明 |
---|---|---|---|
u1 | tag | 1 | 值为6 |
u4 | high_bytes | 1 | 双精度浮点的高四位值 |
u4 | low_bytes | 1 | 双精度浮点的低四位值 |
6.CONSTANT_Class_info
- 表结构:
类 型 | 项目 | 数 目 | 说明 |
---|---|---|---|
u1 | tag | 1 | 值为7 |
u2 | name_index | 1 | 存储constant_pool中的索引值,CONSTANT_Utf8_info类型。 |
- 就像在CONSTANT_Utf8_info表结构一节讲的,CONSTANT_Class_info表并不是真的存储数据,而只是存储了一个CONSTANT_Utf8_info常量的索引值,CONSTANT_Class_info结构更重要的作用是,这个常量值经过CONSTANT_Class_info表一包装它就是用于表述类或接口的符号引用。
7.CONSTANT_String_info
- 表结构:
类 型 | 项目 | 数 目 | 说明 |
---|---|---|---|
u1 | tag | 1 | 值为8 |
u2 | string_index | 1 | 存储constant_pool中的索引值,CONSTANT_Utf8_info类型。 |
- 可能这个类型包装出来的字符串才代表是我们在代码中真正写的字符串常量值吧。
8.CONSTANT_Fieldref_info
- 表结构:
类 型 | 项目 | 数 目 | 说明 |
---|---|---|---|
u1 | tag | 1 | 值为9 |
u2 | class_index | 1 | 存储constant_pool中的索引值,CONSTANT_Class_info类型。记录定义该字段的类或接口。 |
u2 | name_and_type_index | 1 | constant_pool中的索引值,CONSTANT_NameAndType_info类型。指定类或接口中的字段名(name)和字段描述符(descriptor)。 |
- 这个表类型里面又包含了两个常量表的索引,最所以采用索引的方式而不是把表作为自己表结构的一部分是为了节约空间吗?
9.CONSTANT_Methodref_info
- 表结构:
类 型 | 项目 | 数 目 | 说明 |
---|---|---|---|
u1 | tag | 1 | 值为10 |
u2 | class_index | 1 | 存储constant_pool中的索引值,CONSTANT_Class_info类型。记录定义该字段的类或接口。 |
u2 | name_and_type_index | 1 | constant_pool中的索引值,CONSTANT_NameAndType_info类型。指定类或接口中的字段名(name)和字段描述符(descriptor)。 |
10.CONSTANT_InterfaceMethodref_info
- 表结构:
类 型 | 项目 | 数 目 | 说明 |
---|---|---|---|
u1 | tag | 1 | 值为11 |
u2 | class_index | 1 | 存储constant_pool中的索引值,CONSTANT_Class_info类型。记录定义该字段的类或接口。 |
u2 | name_and_type_index | 1 | constant_pool中的索引值,CONSTANT_NameAndType_info类型。指定类或接口中的字段名(name)和字段描述符(descriptor)。 |
11.CONSTANT_NameAndType_info
- 表结构:
类 型 | 项目 | 数 目 | 说明 |
---|---|---|---|
u1 | tag | 1 | 值为12 |
u2 | name_index | 1 | constant_pool中的索引,CONSTANT_Utf8_info类型。指定字段或方法的名称。 |
u2 | name_index | 1 | constant_pool中的索引,CONSTANT_Utf8_info类型。指定字段或方法的描述符。 |
- CONSTANT_Fieldref_info,CONSTANT_Methodref_info,CONSTANT_InterfaceMethodref_info都引用了该表结构,就是因为需要名称和描述符两个字符串。
参考: