Java字节码结构解析

本文通过解析Class文件中字节码的结构,来加深对Java类文件结构的理解。建议先阅读Java类文件结构解析这篇文章。

Test.java

1
2
3
4
5
6
7
8
9
package org.tianbin.clazz;

public class Test{
private int m;

public int inc(){
return m + 1;
}
}

Test.class

1
2
3
4
5
6
7
8
9
10
11
12
13
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

1
2
3
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

1
2
3
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

1
2
07 			
00 11 //常量17 org/tianbin/clazz/Test
字节码 结构 含义
07 tag 值为7,CONSTANT_Class_info
00 11 index 指向全限定名常量项的索引

常量4

1
2
07 
00 12 //常量18 java/lang/Object

结构见常量3

常量5

1
2
3
01 
00 01
6D //m
字节码 结构 含义
01 tag 值为1,CONSTANT_Utf8_info
00 01 length UTF-8编码字符串占用的字节数
6D bytes 长度为length的UTF-8编码的字符串

常量6

1
2
3
01 
00 01
49 //I

结构见常量5

常量7

1
2
3
01
00 06
3C 69 6E 69 74 3E //<init>

结构见常量5

常量8

1
2
3
01 
00 03
28 29 56 //()V

结构见常量5

常量9

1
2
3
01 
00 04
43 6F 64 65 //Code

结构见常量5

常量10

1
2
3
01 
00 0F
4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65 //LineNumberTable

结构见常量5

常量11

1
2
3
01 		
00 03
69 6E 63 //inc

结构见常量5

常量12

1
2
3
01		
00 03
28 29 49 //()I

结构见常量5

常量13

1
2
3
01 		
00 0A
53 6F 75 72 63 65 46 69 6C 65 //SourceFile

结构见常量5

常量14

1
2
3
01 
00 09
54 65 73 74 2E 6A 61 76 61 //Test.java

结构见常量5

常量15

1
2
3
0C 	
00 07
00 08
字节码 结构 含义
0C tag 值为12,CONSTANT_NameAndType_info
00 07 index 指向该字段或方法名称常量的索引
00 08 index 指向该字段或方法描述符常量项的索引

常量16

1
2
3
0C 	
00 05
00 06

结构见常量15

常量17

1
2
3
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

1
2
3
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

常量池之后两个字节标识类的访问标志,用于识别一些类或者接口层次的访问信息。

类索引、父类索引、接口索引

1
2
3
00 03 	类索引 		//org/tianbin/clazz/Test
00 04 父类索引 //java/lang/Object
00 00 接口索引集合大小

字段表集合

1
2
3
4
5
00 01 	fields_count
00 02 access_flags
00 05 name_index //m
00 06 descriptor_index
00 00 attributes_count

方法表集合

1
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属性

1
2
3
00 0D 			attribute_name_index
00 00 00 02 attribute_length
00 0E sourcefile_index //Test.java