JVMJvm使用深入理解Java虚拟机

[JVM]理解Class文件(2)

2017-02-12  本文已影响101人  伤口不该结疤

1. 引言

在上一篇理解Class文件(1):手动解析常量池中,已经对class文件中的常量池做了解析,接下来再看下class文件中的constant_pool后面的其他字段

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]; 
}

将生成的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_flags

3. this_class

this_class 类索引,this_class的值必须是对constant_pool表中项目的一个有效索引值。

4. super_class

super_class 父类索引,对于类来说,super_class的值必须为0或者是对constant_pool表中项目的一个有效索引值

以TestClass为例,来看下access_flags、this_class和super_class的解析

access_flags、this_class和super_class示例

字段说明如下:

图1. TestClass的常量池

2. interfaces_count、interfaces

接口表,interfaces[]数组中的每个成员的值必须是一个对constant_pool表中项目的一个有效索引值,它的长度为interfaces_count。每个成员interfaces[i] 必须为CONSTANT_Class_info类型常量。下面给出两个示例:

以TestClass为例,interfaces_count为0,表示TestClass类没有实现任何接口

interfaces_count为0,则interfaces索引表不再占用任何字节

以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; 
}

参考

上一篇下一篇

猜你喜欢

热点阅读