[JVM]理解Class文件(2)
-
深入理解Java虚拟机
1. 引言
在上一篇理解Class文件(1):手动解析常量池中,已经对class文件中的常量池做了解析,接下来再看下class文件中的constant_pool后面的其他字段
-
ClassFile结构
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
-
示例TestClass文件
将生成的class文件用UltraEdit打开,可以清楚地看到Java编译后生成的字节码,我们要解析的内容也就是这些字节码。
00000000h: CA FE BA BE 00 00 00 33 00 12 0A 00 03 00 0E 07 ;
00000010h: 00 0F 07 00 10 01 00 04 54 45 53 54 01 00 12 4C ;
00000020h: 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 ;
00000030h: 3B 01 00 0D 43 6F 6E 73 74 61 6E 74 56 61 6C 75 ;
00000040h: 65 08 00 11 01 00 06 3C 69 6E 69 74 3E 01 00 03 ;
00000050h: 28 29 56 01 00 04 43 6F 64 65 01 00 0F 4C 69 6E ;
00000060h: 65 4E 75 6D 62 65 72 54 61 62 6C 65 01 00 0A 53 ;
00000070h: 6F 75 72 63 65 46 69 6C 65 01 00 0E 54 65 73 74 ;
00000080h: 43 6C 61 73 73 2E 6A 61 76 61 0C 00 08 00 09 01 ;
00000090h: 00 09 54 65 73 74 43 6C 61 73 73 01 00 10 6A 61 ;
000000a0h: 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 01 00 ;
000000b0h: 0B 74 65 73 74 20 73 74 72 69 6E 67 00 21 00 02 ;
000000c0h: 00 03 00 00 00 01 00 1A 00 04 00 05 00 01 00 06 ;
000000d0h: 00 00 00 02 00 07 00 01 00 01 00 08 00 09 00 01 ;
000000e0h: 00 0A 00 00 00 1D 00 01 00 01 00 00 00 05 2A B7 ;
000000f0h: 00 01 B1 00 00 00 01 00 0B 00 00 00 06 00 01 00 ;
00000100h: 00 00 02 00 01 00 0C 00 00 00 02 00 0D ;
2. access_flags
访问标志,access_flags是一种掩码标志,用于表示某个类或者接口的访问权限及基础属性
表1.access_flags3. this_class
this_class 类索引,this_class的值必须是对constant_pool表中项目的一个有效索引值。
4. super_class
super_class 父类索引,对于类来说,super_class的值必须为0或者是对constant_pool表中项目的一个有效索引值
-
access_flags、super_class和this_class解析示例
以TestClass为例,来看下access_flags、this_class和super_class的解析
access_flags、this_class和super_class示例字段说明如下:
-
access_flags = 00 21 **
由表1.access_flags**可知,该类的访问属性为:ACC_PUBLIC(0x0001) | ACC_SUPER(0x0020) = 0x 00 21 -
super_class = 00 03
super_class父类索引值为3,对应常量池中的第3个常量:#3 = Class #16 // java/lang/Object,即java/lang/Object -
this_class = 00 02
2. interfaces_count、interfaces
接口表,interfaces[]数组中的每个成员的值必须是一个对constant_pool表中项目的一个有效索引值,它的长度为interfaces_count。每个成员interfaces[i] 必须为CONSTANT_Class_info类型常量。下面给出两个示例:
-
示例 1. interfaces_count为0,interfaces索引表不再占用任何字节
以TestClass为例,interfaces_count为0,表示TestClass类没有实现任何接口
interfaces_count为0,则interfaces索引表不再占用任何字节-
示例 2. interfaces_count为1,实现了一个接口
以TestClass2为例,interfaces_count为1,表示实现了一个接口,对应接口名称为常量池中索引值为9(#9 = Class #28 // MyInterface),即TestClass2实现了MyInterface接口
interfaces_count不为0.png TestClass2的常量池3. fields_count、fields
字段计数器,fields_count的值表示当前Class文件fields[]数组的成员个数。fields[]数组中每一项都是一个field_info结构的数据项,它用于表示该类或接口声明的类字段或者实例字段。类字段即被声明为static的字段,实例字段是指未被声明为static的字段。
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
其中field_info包含的attribute_info的通用格式如下:
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
对于任意属性,attribute_name_index必须是对当前Class文件的常量池的有效16位无符号索引。常量池在该索引处的项必须是CONSTANT_Utf8_info结构,表示当前属性的名字。attribute_length项的值给出了跟随其后的字节的长度。
-
fields_count、fields示例
对应常量池索引请参考图1. TestClass的常量池,各字段代表的含义如下表:
Option | Values | Description | ||
---|---|---|---|---|
fields_count | 1 | 表示只有一个字段 | ||
access_flags | 0x001A = ACC_PRIVATE(0x0002) | ACC_STATIC(0x0008) | ACC_FINAL(0x0010) | 表示该字段访问属性为private static final |
name_index | 4 | 表示该字段在常量池的索引值为4,即该字段名称为TEST | ||
descriptor_index | 5 | 对应常量池的索引值为5,即该字段类型为Ljava/lang/String | ||
attributes_count | 1 | 该字段属性个数为1 | ||
attribute_name_index | 6 | 对应常量池的索引值为6,即该字段是一个常量ConstantValue | ||
attribute_length | 2 | ConstantValue_attribute结构的attribute_length项的值固定为2 | ||
constantvalue_index | 7 | 对应常量池的索引值为7,即常量的值为test string |
ConstantValue属性的格式如下:
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 constantvalue_index;
}
-
attribute_name_index
ConstantValue_attribute结构的attribute_length项的值固定为2 -
attribute_length
attribute_name_index项的值,必须是一个对常量池的有效索引 -
constantvalue_index
constantvalue_index项的值,必须是一个对常量池的有效索引
参考
- 深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)
- Java虚拟机规范(Java SE 7).pdf