以下面的TestClazz类为例,

1
2
3
4
5
6
7
8
9
10
11
public class TestClazz {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

编译TestClazz.java后,使用javap -verbose TestClazz命令得到字节码内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
Classfile /C:/Jcode/TestClazz.class
Last modified 2015-4-27; size 396 bytes
MD5 checksum ……
Compiled from "TestClazz.java"
public class TestClazz
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#常量池内容未列出
{
public TestClazz();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1
4: return
LineNumberTable:
line 1: 0
public java.lang.String getName();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #2
4: return
LineNumberTable:
line 5: 0
public void setName(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: putfield #2
5: return
LineNumberTable:
line 9: 0
line 10: 5
}
SourceFile: "TestClazz.java"

使用WinHex(http://www.x-ways.de/winhex.zip)打开TestClazz.class,得到

对内容的分析,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
magic = 0xCAFEBABE //标识文件保存格式
minor_version = 0x0000 //次版本号为0
major_version = 0x0034 //主版本号为52
//编译器版本jdk1.8.0_25,版本号52.0
constant_pool_count = 0x0015 //常量池容量为21(1-20)
constant_pool = ……
#1{
tag = 0x0A //类中方法的符号引用
index = 0x0004 //-->#4
index = 0x0011 //-->#17
}
#2{
tag= 0x09 //字段的符号引用
index= 0x0003 //-->#3
index= 0x0012 //-->#18
}
#3{
tag = 0x07 //类或接口的符号引用
index = 0x0013 //-->19
}
#4{
tag = 0x07 //类或接口的符号引用
index = 0x0014 //-->#20
}
#5{
tag = 0x01 //UTF-8编码的字符串
length = 0x0004
bytes = 0x6E,0x61,0x6D,0x65 //字符串"name"
}
#6{
tag = 0x01 //UTF-8编码的字符串
length = 0x0012
bytes = 0x4C,0x6A,0x61,0x76,0x61,0x2F,0x6C,0x61,0x6E,0x67,0x2F,0x53,0x74,0x72,0x69,0x6E,0x67,0x3B
//字符串"Ljava/lang/String;"
}
#07{
tag = 0x01 //UTF-8编码的字符串
length = 0x0006
bytes = 0x3C,0x69,0x6E,0x69,0x74,0x3E //字符串"<init>"
}
#08{
tag = 0x01 //UTF-8编码的字符串
length = 0x0003
bytes = 0x28,0x29,0x56 //字符串"()V"
}
#09{
tag = 0x01 //UTF-8编码的字符串
length = 0x0004
bytes = 0x43,0x6F,0x64,0x65 //字符串"Code"
}
#10{
tag = 0x01 //UTF-8编码的字符串
length = 0x000F
bytes = 0x4C,0x69,0x6E,0x65,0x4E,0x75,0x6D,0x62,0x65,0x72,0x54,0x61,0x62,0x6C,0x65
//字符串"LineNumberTable"
}
#11{
tag = 0x01 //UTF-8编码的字符串
length = 0x0007
bytes = 0x67,0x65,0x74,0x4E,0x61,0x6D,0x65
//字符串"getName"
}
#12{
tag = 0x01 //UTF-8编码的字符串
length = 0x0014
bytes = 0x28,0x29,0x4C,0x6A,0x61,0x76,0x61,0x2F,0x6C,0x61,0x6E,0x67,0x2F,0x53,0x74,0x72,0x69,0x6E,0x67,0x3B
//字符串"()Ljava/lang/String;"
}
#13{
tag = 0x01 //UTF-8编码的字符串
length = 0x0007
bytes = 0x73,0x65,0x74,0x4E,0x61,0x6D,0x65
//字符串"setName"
}
#14{
tag = 0x01 //UTF-8编码的字符串
length = 0x0015
bytes = 0x28,0x4C,0x6A,0x61,0x76,0x61,0x2F,0x6C,0x61,0x6E,0x67,0x2F,0x53,0x74,0x72,0x69,0x6E,0x67,0x3B,0x29,0x56
//字符串"(Ljava/lang/String;)V"
}
#15{
tag = 0x01 //UTF-8编码的字符串
length = 0x000A
bytes = 0x53,0x6F,0x75,0x72,0x63,0x65,0x46,0x69,0x6C,0x65 //字符串"SourceFile"
}
#16{
tag = 0x01 //UTF-8编码的字符串
length = 0x000E
bytes = 0x54,0x65,0x73,0x74,0x43,0x6C,0x61,0x7A,0x7A,0x2E,0x6A,0x61,0x76,0x61
//字符串"TestClazz.java"
}
#17{
tag = 0x0C //字段或方法的部分符号引用
index = 0x0007 //-->#7
index = 0x0008 //-->#8
}
#18{
tag = 0x0C //字段或方法的部分符号引用
index = 0x0005 //-->#5
index = 0x0006 //-->#6
}
#19{
tag = 0x01 //UTF-8编码的字符串
length = 0x0009
bytes = 0x54,0x65,0x73,0x74,0x43,0x6C,0x61,0x7A,0x7A
//字符串"TestClazz.java"
}
#20{
tag = 0x01 //UTF-8编码的字符串
length = 0x0010
bytes = 0x6A,0x61,0x76,0x61,0x2F,0x6C,0x61,0x6E,0x67,0x2F,0x4F,0x62,0x6A,0x65,0x63,0x74
//字符串"java/lang/Object"
}
access_flags = 0x0021 //访问标志0x0001|0x0020 = 0x0021
//对应flags: ACC_PUBLIC, ACC_SUPER
this_class = 0x0003 //类名TestClazz.java
super_class = 0x0004 //父类名java/lang/Object
interfaces_count = 0x0000 //实现的接口数为0
fields_count = 0x0001 //字段表集合容量为1
fields = ……
{
access_flags = 0x0002 //字段为private
name_index = 0x0005 //-->#5
descriptor_index = 0x0006 //-->#6
//private Ljava/lang/String; name
attributes_count = 0x0000
}
methods_count = 0x0003 //方法表集合容量为3
methods = ……
#0{
access_flags = 0x0001 //方法为public
name_index = 0x0007
descriptor_index = 0x0008
//public TestClazz()
attributes_count = 0x0001
{
attribute_name_index = 0x0009
attribute_length = 0x0000001D
max_stack = 0x0001
max_locals = 0x0001
code_length = 0x00000005
code = 2AB70001B1
exception_table_length = 0x0000
attributes_count = 0x0001
{
attribute_name_index = 0x000A
attribute_length = 0x00000006
line_number_table_length = 0x0001
{
start_pc = 0x0000
line_number = 0x0001
}
}
}
}
#1{
access_flags = 0x0001 //方法为public
name_index = 0x000B
descriptor_index = 0x000C
//public Ljava/lang/String; getName()
attributes_count = 0x0001
{
attribute_name_index = 0x0009
attribute_length = 0x0000001D
max_stack = 0x0001
max_locals = 0x0001
code_length = 0x00000005
code = 2AB40002B0
exception_table_length = 0x0000
attributes_count = 0x0001
{
attribute_name_index = 0x000A
attribute_length = 0x00000006
line_number_table_length = 0x0001
{
start_pc = 0x0000
line_number = 0x0005
}
}
}
}
#2{
access_flags = 0x0001 //方法为public
name_index = 0x000D
descriptor_index = 0x000E
//public void setName(Ljava/lang/String;)
attributes_count = 0x0001
{
attribute_name_index = 0x0009
attribute_length = 0x00000022
max_stack = 0x0002
max_locals = 0x0002
code_length = 0x00000006
code = 2A2BB50002B1
exception_table_length = 0x0000
attributes_count = 0x0001
{
attribute_name_index = 0x000A
attribute_length = 0x0000000A
line_number_table_length = 0x0002
#0{
start_pc = 0x0000
line_number = 0x0009
}
#1{
start_pc = 0x0005
line_number = 0x000A
}
}
}
}
attributes_count = 0x0001 //属性表集合容量为1
attributes = ……
{
attribute_name_index = 0x000F
attribute_length = 0x00000002
sourcefile_index = 0x0010
}
参考资料

《深入理解Java虚拟机》