class文件解析

Class.class文件解析

最近在看jvm相关的书,看到关于class文件结构的部分。就自己写了一个类并编译成class文件尝试着自己来解析一下加深认识和印象(为了方便学习去除了某些重复的方法)。

class文件全部内容如下所示:

CAFEBABE 00000031 00340A00 08002509 00050026 09000500 270A0028 00290700 2A0A002B 002C0A00 2B002D07 002E0700 2F010005 6669656C 64010012 4C6A6176 612F6C61 6E672F53 7472696E 673B0100 06764669 656C6401 00067346 69656C64 01000674 4669656C 64010006 3C696E69 743E0100 03282956 01000443 6F646501 000F4C69 6E654E75 6D626572 5461626C 65010012 4C6F6361 6C566172 6961626C 65546162 6C650100 04746869 73010017 4C636F6D 2F74716D 616C6C2F 74657374 2F436C61 73733B01 00086765 74466965 6C640100 1428294C 6A617661 2F6C616E 672F5374 72696E67 3B010008 73657446 69656C64 01001528 4C6A6176 612F6C61 6E672F53 7472696E 673B2956 01000967 65747346 69656C64 01000973 65747346 69656C64 01000665 7175616C 73010015 284C6A61 76612F6C 616E672F 4F626A65 63743B29 5A010001 6F010012 4C6A6176 612F6C61 6E672F4F 626A6563 743B0100 0661436C 61737301 00086861 7368436F 64650100 03282949 01000A53 6F757263 6546696C 6501000A 436C6173 732E6A61 76610C00 0F00100C 000A000B 0C000D00 0B070030 0C003100 32010015 636F6D2F 74716D61 6C6C2F74 6573742F 436C6173 73070033 0C001C00 1D0C0021 00220100 1A636F6D 2F74716D 616C6C2F 74657374 2F537570 6572436C 61737301 001E636F 6D2F7471 6D616C6C 2F746573 742F5375 70657249 6E746572 66616365 0100106A 6176612F 6C616E67 2F4F626A 65637401 00086765 74436C61 73730100 1328294C 6A617661 2F6C616E 672F436C 6173733B 0100106A 6176612F 6C616E67 2F537472 696E6700 21000500 08000100 09000400 02000A00 0B000000 42000C00 0B000000 0A000D00 0B000000 82000E00 0B000000 07000100 0F001000 01001100 00002F00 01000100 0000052A B70001B1 00000002 00120000 00060001 00000007 00130000 000C0001 00000005 00140015 00000001 00160017 00010011 0000002F 00010001 00000005 2AB40002 B0000000 02001200 00000600 01000000 12001300 00000C00 01000000 05001400 15000000 01001800 19000100 11000000 3E000200 02000000 062A2BB5 0002B100 00000200 12000000 0A000200 00001600 05001700 13000000 16000200 00000600 14001500 00000000 06000A00 0B000100 09001A00 17000100 11000000 1C000100 00000000 04B20003 B0000000 01001200 00000600 01000000 1A000900 1B001900 01001100 00003300 01000100 0000052A B30003B1 00000002 00120000 000A0002 0000001E 0004001F 00130000 000C0001 00000005 000D000B 00000001 001C001D 00010011 00000089 00020003 0000003F 2A2BA600 0504AC2B C6000E2A B600042B B60004A5 000503AC 2BC00005 4D2AB400 02C60011 2AB40002 2CB40002 B60006A7 000F2CB4 0002C700 0704A700 0403AC00 00000200 12000000 12000400 00002300 07002400 18002600 1D002800 13000000 20000300 00003F00 14001500 00000000 3F001E00 1F000100 1D002200 20001500 02000100 21002200 01001100 00003D00 01000100 0000132A B40002C6 000D2AB4 0002B600 07A70004 03AC0000 00020012 00000006 00010000 002E0013 0000000C 00010000 00130014 00150000 00010023 00000002 0024

 

要想知道文件是啥意思首先得知道文件结构是什么样子的,下表是java的class文件格式

 

class文件结构
类型 名称 数量
u4 magic 1
u2 minor_version 1
u2 major_version 1
u2 constant_pool_count 1
cp_info constant_pool constant_pool_count - 1
u2 access_flags 1
u2 this_class 1
u2 super_class 1
u2 interfaces_count 1
u2 interfaces interfaces_count
u2 fields_count 1
field_info fields fields_count
u2 methods_count 1
method_info methods methods_count
u2 attribute_count 1
attribute_info attributes attributes_count

 

根据以上表格看到前4个字节为magic魔数字段(每一种文件都会有一种特定的值),这里是CAFEBABE代表是class文件类型。接下来就是次版本和主版本了 00000031为49表示此文件可以被1.5及以上版本的jvm执行。之后就是常量池的数量0034转为十进制值为52即有1-51共51个常量数据。

有关于常量项的数据结构如下表所示:

池中常量项结构
常量 项目 类型 描述
CONSTANT_Utf8_info tag u1 值为1
length u2 UTF-8编码的字符串占用字节数
bytes u1 长度为length的UTF-8编码的字符串
CONSTANT_Integer_info tag u1 值为3
bytes u4 按照高位在前存储的int值
CONSTANT_Float_info tag u1 值为4
bytes u4 按照高位在前存储的float值
CONSTANT_Long_info tag u1 值为5
bytes u8 按照高位在前存储的long值
CONSTANT_Double_info tag u1 值为6
bytes u8 按照高位在前存储的double值
CONSTANT_Class_info tag u1 值为7
index u2 指向全限定名常量项的索引
CONSTANT_String_info  tag u1 值为8
index u2 指向字符串字面值的索引
CONSTANT_Fieldref_info tag u1 值为9
index u2 指向声明字段的类或接口描述符CONSTANT_Class_info的索引项
index u2 指向字段描述符CONSTANT_NameAndType的索引项
CONSTANT_Methodref_info tag u1 值为10
index u2 指向声明方法的类描述符CONSTANT_Class_info的索引项
index u2 指向方法描述符CONSTANT_NameAndType_info的索引项
CONSTANT_InterfaceMethodref_info tag u1 值为11
index u2 指向声明方法的类描述符CONSTANT_Class_info的索引项
index u2 指向方法描述符CONSTANT_NameAndType_info的索引项
CONSTANT_NameAndType_info tag u1 值为12
index u2 指向该字段或方法名称常量项的索引
index u2 指向该字段或方法描述符常量项的索引
CONSTANT_MethodHandle_info tag u1 值为15
reference_kind u1 值必须在1~9之间(包括1和9),它决定了方法句柄的类型。方法句柄类型的值表示方法句柄的字节码行为
reference_index u2 值必须是对常量池的有效索引
CONSTANT_MethodType_info tag u1 值为16
descriptor_index u2 值必须是对当前常量池的有效索引,常量池在该索引处的项必须是CONSTANT_Utf8_info结构,表示方法的描述符
CONSTANT_InvokeDynamic_info tag u1 值为18
bootstrap_method_attr_index u2 值必须是对当前的Class文件中引导方法表的bootstrap_method[]数组的有效索引
name_and_type_index u2 值必须是对当前常量池的有效索引,常量池在该索引出的项必须是CONSTANT_NameAndType_info结构,表示方法名和方法描述符

 

根据以上表格解析出常量数据为

#1 0A 0008 0025 Methodref #8.#37

#2 09 0005 0026 Fieldref #8.#38

#3 09 0005 0027 Fieldref #8.#39

#4 0A 0028 0029 Methodref #40.#41

#5 07 002A Class #42

#6 0A 002B 002C Methodref #43.#44 

#7 0A 002B 002D Methodref #43.#45

#8 07 002E Class #46

#9 07 002F Class #47

#10 01 0005 66 69 65 6C 64 Utf8 field

#11 01 0012 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B Utf8 Ljava/lang/String;

#12 01 0006 76 46 69 65 6C 64 Utf8 vField

#13 01 0006 73 46 69 65 6C 64 Utf8 sField

#14 01 0006 74 46 69 65 6C 64 Utf8 tField

#15 01 0006 3C 69 6E 69 74 3E Utf8 <init>

#16 01 0003 28 29 56 Utf8 ()V

#17 01 0004 43 6F 64 65 Utf8 Code 

#18 01 000F 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65 Utf8 LineNumberTable

#19 01 0012 4C 6F 63 61 6C 56 61 72 69 61 62 6C 65 54 61 62 6C 65 Utf8 LocalVariableTable

#20 01 0004 74 68 69 73 Utf8 this

#21 01 0017 4C 63 6F 6D 2F 74 71 6D 61 6C 6C 2F 74 65 73 74 2F 43 6C 61 73 73 3B Utf8 Lcom/tqmall/test/Class;

#22 01 0008 67 65 74 46 69 65 6C 64 Utf8 getField

#23 01 0014 28 29 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B Utf8 ()Ljava/lang/String;

#24 01 0008 73 65 74 46 69 65 6C 64 Utf8 setField

#25 01 0015 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 Utf8 (Ljava/lang/String;)V

#26 01 0009 67 65 74 73 46 69 65 6C 64 Utf8 getsField

#27 01 0009 73 65 74 73 46 69 65 6C 64 Utf8 setsField

#28 01 0006 65 71 75 61 6C 73 Utf8 equals

#29 01 0015 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 3B 29 5A Utf8 (Ljava/lang/Object;)Z

#30 01 0001 6F Utf8 o

#31 01 0012 4C 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 3B Utf8 Ljava/lang/Object;

#32 01 0006 61 43 6C 61 73 73 Utf8 aClass

#33 01 0008 68 61 73 68 43 6F 64 65 Utf8 hashCode

#34 01 0003 28 29 49 Utf8 ()I

#35 01 000A 53 6F 75 72 63 65 46 69 6C 65 Utf8 SourceFile

#36 01 000A 43 6C 61 73 73 2E 6A 61 76 61 Utf8 Class.java

#37 0C 000F 0010 NameAndType #15:#16 

#38 0C 000A 000B NameAndType #10:#11

#39 0C 000D 000B NameAndType #13:#11

#40 07 0030 Class #48

#41 0C 0031 0032 NameAndType #49:#50

#42 01 0015 63 6F 6D 2F 74 71 6D 61 6C 6C 2F 74 65 73 74 2F 43 6C 61 73 73 Utf8 com/tqmall/test/Class

#43 07 0033 Class #51

#44 0C 001C 001D NameAndType #28:#29

#45 0C 0021 0022 NameAndType #33:34

#46 01 001A 63 6F 6D 2F 74 71 6D 61 6C 6C 2F 74 65 73 74 2F 53 75 70 65 72 43 6C 61 73 73 Utf8 com/tqmall/test/SuperClass

#47 01 001E 63 6F 6D 2F 74 71 6D 61 6C 6C 2F 74 65 73 74 2F 53 75 70 65 72 49 6E 74 65 72 66 61 63 65 Utf8 com/tqmall/test/SuperInterface

#48 01 0010 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 Utf8 java/lang/Object

#49 01 0008 67 65 74 43 6C 61 73 73 Utf8 getClass

#50 01 0013 28 29 4C 6A 61 76 61 2F 6C 61 6E 67 2F 43 6C 61 73 73 3B Utf8 ()Ljava/lang/Class;

#51 01 0010 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 Utf8 java/lang/String

按照class文件结构表格接下来的0021就是u2的access_flags了根据访问标志表对应的标志值应该为0x0020|0x0001即ACC_PUBLIC和ACC_SUPER。之后的0005是u2的this_class对应的是类索引指向的是常量池的一条数据#5。之后的0008是u2的super_class对应的是父类索引指向的是常量池的一条数据#8。接下来的0001是u2的interfaces_count对应的是实现的接口数量,因为类可以实现多个接口所以会有这个字段,这里的值是1说明实现了一个接口。下面的一个u2的数据是0009就是实现的接口的索引指向常量池的一条数据#9。之后的数据0004为fields_count,说明该类共有4个field_info信息。第一个field对应接下来的0002 000A 000B 0000分别对应access_flags、name_index、descriptor_index、attributes_count、attribute值分别为ACC_PRIVATE、#10、#11、0。因为attrbutes_count为0所以就没有attrbute_info信息了。第二个0042 000C 000B 0000对应值ACC_PRIVATE和ACC_VOLATILE、#12、#11、0。第三个000A 000D 000B 0000对应值ACC_PRIVATE和ACC_STATIC、#13、#11、0。第四个0082 000E 000B 0000对应值ACC_PRIVATE和ACC_TRANSIENT、#14、#11、0。

接下来的0007对应的就是method_count信息了,说明共有7个method_info信息。

第一个0001 000F 0010 0001 0011 0000002F 0001 0001 00000005 2A B7 00 01 B1 0000 0002 0012 00000006 0001 0000 0007 0013 0000000C 0001 0000 0005 0014 0015 0000分别对应access_flags、name_index、descriptor_index、attributes_count、attributes值分别为ACC_PUBLIC、#15、#16、1、#17(attribute_name_index常量表查询得到Code属性表)、47(attribute_length)、1(max_stack)、1(max_locals)、5(code_length)、aload_0、invokespecial、#1、return、0(异常表数量)、2(属性表数量)、#18(attibute_name_index常量表查询得到LineNumberTable属性表)、6(attribute_length)、1(line_number_table_length)、0(start_pc字节码行号)、7(line_number源码行号)、#19(attribute_name_index常量表查询得到LocalVariableTable属性表)、12(attribute_length)、1(local_variable_table_length)、0(start_pc变量生命周期开始的字节码偏移量)、5(length变量作用范围覆盖的长度)、#20(name_index)、#21(decriptor_index)、0(index变量在战阵局部变量表中Slot的位置,double和long64位时占用index和index+1)。

第二个0001 0016 0017 0001 0011 0000002F 0001 0001 00000005 2A B4 00 02 B0 0000 0002 0012 00000006 0001 0000 0012 0013 0000000C 0001 0000 0005 0014 0015 0000对应值为ACC_PUBLIC、#22、#23、1、#17、47、1、1、5、aload_0、getfield、#2、areturn、0、2、#18、6、1、0、18、#19、12、1、0、5、#20、#21、0。

第三个0001 0018 0019 0001 0011 0000003E 0002 0002 00000006 2A 2B B5 00 02 B1 0000 0002 0012 0000000A 0002 0000 0016 0005 0017 0013 00000016 0002 0000 0006 0014 0015 0000 0000 0006 000A 000B 0001分别对应值为ACC_PUBLIC(access_flags)、#24(name_index)、#25(descriptor_index)、1(attributes_count)、#17(attribute_name_index常量表查询得到Code属性表)、62(attribute_length)、2(max_stack)、2(max_locals)、6(code_length)、aload_0、aload_1、putfield、#2、return、0(异常表数量)、2(属性表数量)、#18(attibute_name_index常量表查询得到LineNumberTable属性表)、10(attribute_length)、2(line_number_table_length)、0(start_pc字节码行号)、22(line_number源码行号)、5(start_pc字节码行号)、23(line_number源码行号)、#19(attribute_name_index常量表查询得到LocalVariableTable属性表)、22(attribute_length)、2(local_variable_table_length)、0(start_pc变量生命周期开始的字节码偏移量)、6(length变量作用范围覆盖的长度)、#20(name_index)、#21(decriptor_index)、0(index变量在战阵局部变量表中Slot的位置,double和long64位时占用index和index+1)、0(start_pc变量生命周期开始的字节码偏移量)、6(length变量作用范围覆盖的长度)、#10(name_index)、#11(decriptor_index)、1(index变量在战阵局部变量表中Slot的位置,double和long64位时占用index和index+1)。

第四个0009 001A 0017 0001 0011 0000001C 0001 0000 00000004 B2 00 03 B0 0000 0001 0012 00000006 0001 0000 001A分别对应值为ACC_PUBLIC和ACC_STATIC、#26、#23、1、#17(Code)、28、1、0、4、getstatic、#3、areturn、0、1、#18、6、1、0、26。

第五个0009 001B 0019 0001 0011 00000033 0001 0001 00000005 2A B3 00 03 B1 0000 0002 0012 0000000A 0002 0000 001E 0004 001F 0013 0000000C 0001 0000 0005 000D 000B 0000对应值为ACC_PUBLIC和ACC_STATIC、#27、#25、1、#17、51、1、1、5、aload_0、putstatic、#3、return、0、2、#18、10、2、0、30、4、31、#19、12、1、0、5、13、11、0。

第六个0001 001C 001D 0001 0011 00000089 0002 0003 0000003F 2A 2B A6 00 05 04 AC 2B C6 00 0E 2A B6 00 04 2B B6 00 04 A5 00 05 03 AC 2B C0 00 05 4D 2A B4 00 02 C6 00 11 2A B4 00 02 2C B4 00 02 B6 00 06 A7 00 0F 2C B4 00 02 C7 00 07 04 A7 00 04 03 AC 0000 0002 0012 00000012 0004 0000 0023 0007 0024 0018 0026 001D 0028 0013 00000020 0003 0000 003F 0014 0015 0000 0000 003F 001E 001F 0001 001D 0022 0020 0015 0002对应值为ACC_PUBLIC、#28、#29、1、#17、137、2、3、63、aload_0、aload_1、if_acmpne、#5、#4、ireturn、aload_1、ifnull、#14、aload_0、invokevirtual、#4、aload_1、invokevirtual、#4、if_acmpeq、#5、#3、ireturn、aload_1、checkcast、#5、astore_2、aload_0、getfield、#2、ifnull、#17、aload_0、getfield、#2、aload_2、getfield、#2、invokevirtual、#6、goto、#15、aload_2、getfield、#2、ifnotnull、#7、iconst_1、goto、#4、iconst_0、ireturn、0、2、#18、18、4、0、35、7、36、24、39、29、40、#19、32、3、0、63、#20、#21、0、0、63、#30、#31、1、29、34、#32、#21、2。

第七个0001 0021 0022 0001 0011 0000003D 0001 0001 00000013 2A B4 00 02 C6 00 0D 2A B4 00 02 B6 00 07 A7 00 04 03 AC 0000 0002 0012 00000006 0001 0000 002E 0013 0000000C 0001 0000 0013 0014 0015 0000对应值为ACC_PUBLIC、#33、#34、1、#17、61、1、1、19、aload_0、getfield、nop、iconst_m1、ifnull、nop、fconst_2、aload_0、invokevirtual、nop、iconst_4、goto、nop、iconst_1、iconsst_0、ireturn、0、2、#18、6、1、0、46、#19、12、1、0、19、#20、#21、0。

接下来的就是类的attributes信息了,0001为attributes_count值为1。

然后 0023 00000002 0024对应值为#35、2、#36。

猜你喜欢

转载自cccai-1234.iteye.com/blog/2342096