本文通过解析Class文件中字节码的结构,来加深对Java类文件结构的理解。建议先阅读Java类文件结构解析这篇文章。
Test.java
package org.tianbin.clazz;
public class Test{
private int m;
public int inc(){
return m + 1;
}
}
Test.class
CA FE BA BE 00 00 00 34 00 13 0A 00 04 00 0F 09 00 03 00 10 07 00
11 07 00 12 01 00 01 6D 01 00 01 49 01 00 06 3C 69 6E 69 74 3E 01
00 03 28 29 56 01 00 04 43 6F 64 65 01 00 0F 4C 69 6E 65 4E 75 6D
62 65 72 54 61 62 6C 65 01 00 03 69 6E 63 01 00 03 28 29 49 01 00
0A 53 6F 75 72 63 65 46 69 6C 65 01 00 09 54 65 73 74 2E 6A 61 76
61 0C 00 07 00 08 0C 00 05 00 06 01 00 16 6F 72 67 2F 74 69 61 6E
62 69 6E 2F 63 6C 61 7A 7A 2F 54 65 73 74 01 00 10 6A 61 76 61 2F
6C 61 6E 67 2F 4F 62 6A 65 63 74 00 21 00 03 00 04 00 00 00 01 00
02 00 05 00 06 00 00 00 02 00 01 00 07 00 08 00 01 00 09 00 00 00
1D 00 01 00 01 00 00 00 05 2A B7 00 01 B1 00 00 00 01 00 0A 00 00
00 06 00 01 00 00 00 03 00 01 00 0B 00 0C 00 01 00 09 00 00 00 1F
00 02 00 01 00 00 00 07 2A B4 00 02 04 60 AC 00 00 00 01 00 0A 00
00 00 06 00 01 00 00 00 07 00 01 00 0D 00 00 00 02 00 0E
魔数
CA FE BA BE
class文件的头4个字节,用于验证该文件是否能够被虚拟机接受
主次版本号
00 00 00 34
魔数后4个字节,第5个和第6个字节是次版本号(Minor Version),第7个和第8个字节是主版本号(Major Version),Test.java文件使用JDK1.8进行编译,所以主版本号为00 34
,十进制表示为52。
常量池
结构:容量计数器(u2类型) + 常量
00 13
容量计算器,计数从1开始,目的是满足某些常量池的索引值的数据在特定情况下需要表达“不引用任何一个常量池”的含义。当前容量计算器值为19,表示常量池中有18项常量,索引值范围为1~18。
常量1
0A
00 04 //java/lang/Object
00 0F //<init>
字节码 | 结构 | 含义 |
---|---|---|
0A | tag | 值为10,CONSTANT_Methodref_info |
00 04 | index | 指向声明方法的类描述符CONSTANT_Class_info的索 |
00 0F | index | 指向名称及类型描述符CONSTANT_NameAndType的索引项 |
常量2
09
00 03 //org/tianbin/clazz/Test
00 10 //m
字节码 | 结构 | 含义 |
---|---|---|
09 | tag | 值为9,CONSTANT_Fieldref_info |
00 03 | index | 指向声明字段的类或者接口描述符CONSTANT_Class_info的索引项 |
00 10 | index | 指向字段描述符CONSTANT_NameAndType的索引项 |
常量3
07
00 11 //常量17 org/tianbin/clazz/Test
字节码 | 结构 | 含义 |
---|---|---|
07 | tag | 值为7,CONSTANT_Class_info |
00 11 | index | 指向全限定名常量项的索引 |
常量4
07
00 12 //常量18 java/lang/Object
结构见常量3
常量5
01
00 01
6D //m
字节码 | 结构 | 含义 |
---|---|---|
01 | tag | 值为1,CONSTANT_Utf8_info |
00 01 | length | UTF-8编码字符串占用的字节数 |
6D | bytes | 长度为length的UTF-8编码的字符串 |
常量6
01
00 01
49 //I
结构见常量5
常量7
01
00 06
3C 69 6E 69 74 3E //<init>
结构见常量5
常量8
01
00 03
28 29 56 //()V
结构见常量5
常量9
01
00 04
43 6F 64 65 //Code
结构见常量5
常量10
01
00 0F
4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65 //LineNumberTable
结构见常量5
常量11
01
00 03
69 6E 63 //inc
结构见常量5
常量12
01
00 03
28 29 49 //()I
结构见常量5
常量13
01
00 0A
53 6F 75 72 63 65 46 69 6C 65 //SourceFile
结构见常量5
常量14
01
00 09
54 65 73 74 2E 6A 61 76 61 //Test.java
结构见常量5
常量15
0C
00 07
00 08
字节码 | 结构 | 含义 |
---|---|---|
0C | tag | 值为12,CONSTANT_NameAndType_info |
00 07 | index | 指向该字段或方法名称常量的索引 |
00 08 | index | 指向该字段或方法描述符常量项的索引 |
常量16
0C
00 05
00 06
结构见常量15
常量17
01
00 16
6F 72 67 2F 74 69 61 6E 62 69 6E 2F 63 6C 61 7A 7A 2F 54 65 73 74 //org/tianbin/clazz/Test
结构见常量5
常量18
01
00 10
6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 //java/lang/Object
结构见常量5
访问标志
00 21
常量池之后两个字节标识类的访问标志,用于识别一些类或者接口层次的访问信息。
类索引、父类索引、接口索引
00 03 类索引 //org/tianbin/clazz/Test
00 04 父类索引 //java/lang/Object
00 00 接口索引集合大小
字段表集合
00 01 fields_count
00 02 access_flags
00 05 name_index //m
00 06 descriptor_index
00 00 attributes_count
方法表集合
00 02 method_count //<init> inc
init
字节码 | 结构名称 | 含义 |
---|---|---|
00 01 | access_flag | |
00 07 | name_index | |
00 08 | descriptor_index | |
00 01 | attributes_count | |
00 09 | attributes_name_index | Code |
00 00 00 1D | attribute_length | |
00 01 | max_stack | |
00 01 | max_local | |
00 00 00 05 | code_length | |
2A B7 00 01 B1 | code | |
00 00 | exception_table_length | |
00 01 | attributes_count | |
00 0A | attributes_name_index | LineNumberTable |
00 00 00 06 | attribute_length | |
00 01 | line_number_table_length | |
00 00 | start_pc | |
00 03 | line_number |
inc
字节码 | 结构名称 | 含义 |
---|---|---|
00 01 | access_flag | |
00 0B | name_index | inc |
00 0C | descriptor_index | |
00 01 | attributes_count | |
00 09 | attributes_name_index | Code |
00 00 00 1F | attribute_length | |
00 02 | max_stack | |
00 01 | max_local | |
00 00 00 07 | code_length | |
2A B4 00 02 04 60 AC | code | |
00 00 | exception_table_length | |
00 01 | attributes_count | |
00 0A | attributes_name_index | LineNumberTable |
00 00 00 06 | attribute_length | |
00 01 | line_number_table_length | |
00 00 | start_pc | |
00 07 | line_number |
Class文件的属性表
00 01
属性表的大小
SourceFile属性
00 0D attribute_name_index
00 00 00 02 attribute_length
00 0E sourcefile_index //Test.java