
今天进入最关键也是最重要部分方法表,也是有一定难度。
定义方法访问标记
00 01 :表示一个 public 方法,这是一个构造方法。
00 0B : 对应常量池 # 11 <init>
00 0C : 对应常量池 #12 ()V
00 01 : 说明这个方法本身只有一个属性,每一个方法表都有 code 属性保存这个方法的结构
00 0D : #13 = Utf8 Code
00 00 00 43 (67): 字节长度

00 02 :max_stack
00 01 : max_local
00 00 00 11: (17)code_length 表示该方法所包含字节码的字节数以及具体的指令码
我们可以根据 code_length 向后数 17 字节,这是函数 code 执行指令
2A B7 00 01 2A 12 02 B5 00 03 2A 10 0A B5 00 04 B1

此图与上面字节码相对应。图中出现的为助记符,助记符和16进制对应
-
2A (aload_0)
可以通过在 jclasslib 面板点击助记符aload_o
跳转到 JVM 官方 JVM 规范的中助记符对应章节。
aload 助记符
n 表示索引,是局部变量数组的索引,在此位置(n)会包含一个引用,而且将该局部变量推到栈顶 -
B7 (invokespecial)
invokespecial 助记符
表示调用父类的构造方法,而且还有参数为其后面的两个字节,
00 01 :#1 = Methodref #6.#28 // java/lang/Object."<init>":()V
表示父类的构造方法调用 Object 的 init 方法 -
0A
-
12(ldc)
ldc 助记符
从常量池获取元素
-
02 #2 = String #29 // basic
-
B5 (putfiled)
putfield
为对象设置属性,属性为
00 03 #3 = Fieldref #5.#30 // com/zidea/Tut.title:Ljava/lang/String;
上面是从常量池读取 basic 字面量赋值给对象属性 title。 -
10(bipush)
bipush
具体赋值为其后字节 0A(10)
将 10 放置到栈顶然后准备给 courses 属性进行赋值,内容重复大家可以自己感受一下 -
B1(return)
return
表示方法执行完毕,返回为 void。
随后两个字节使用表示异常表信息的数量,如果为 0 表示没有异常信息表
00 00
表示异常表信息,异常表数量为 0 没有异常信息。
00 02
表示存在两个属性,随后
00 0E
这里的 00 0E(14) #14 = Utf8 LineNumberTable 对应常量池内容,LineNumberTable 用途是将字节码和实际代码行号进行对应便于调试查找问题
00 00 00 0E
00 03 00 00 00 03 00 04 00 04 00 0A 00 05
00 03 表示有三个对应关系
-
00 00 00 03 :0 对应 3
-
00 04 00 04
-
00 0A 00 05 :10 对应 5 行代码
LineNumberTable
[图片上传失败...(image-950363-1556845759146)]
-
00 0F (15) #15 = Utf8 LocalVariableTable
表示第二个属性名字为 15 对应表示局部变量表
00 00 00 0C 表示连续 12 字节表示局部变量
00 01 00 00 00 11 00 10 00 11 00 00
-
00 01 表示构造方法里局部变量的个数
-
00 00 和 00 11 表示局部变量开始和结束的位置
-
00 10 (16)表示局部变量在常量池位置 #16 = Utf8 this
-
00 11 (17)对局部变量的描述 #17 = Utf8 Lcom/zidea/Tut;
-
00 00 可以跳过去
我们知道 java 中每一个方法都是访问到this
其实在 JVM 编译时,this 是作为第一个参数传入到方法才能被使用。
我们第一个构造方法的字节码分析到此就结束,可以开始下一个方法也就是getTitle
,相同内容我就不多赘述了,大家可以自动手查一查。 -
00 01 (access_flag) ACC_PUBLIC)
00 12 : #18 = Utf8 getTitle(方法名)
00 13 : #19 = Utf8 ()Ljava/lang/String;(描述符)
00 01 :表示方法属性
00 0D :对应 code
00 00 00 2F(47)字节表示 code 的信息
00 01 :
00 01 :局部变量表为 this。
00 00 00 05 :表示该方法字节码所占长度,可以向后数 5 个字节。 -
2A aload_0
-
B4 (getfield) 从成员变量获取值 参数为 00 03 表示指向常量池 3 元素 #3 = Fieldref #5.#30 // com/zidea/Tut.title:Ljava/lang/String;
-
B0(Return reference from method)表示返回一个引用,因为字符串 ”basic“ 是一个引用对象所以这里返回字符串的引用。
-
00 00 :表示没有异常表
-
00 02 :表示两个属性
-
00 0E : 第一个属性为 LineNumberTable
回顾一下 LineNumberTable 的属性有哪些 -
attribute_name_index u2
-
attribute_length u4
-
line_number_table_length
- start_pc
- line_number
-
00 00 00 06 (属性长度为 6 )
00 01 00 00 00 08
表示偏移量为 0 对应行号 8 ,行号 8 内容为return title;
。
- 00 0F 局部变量表
- 00 00 00 0C 表示局部变量的长度 12 数 12 字节
00 01 00 00 00 05 00 10 00 11 00 00
表示有一个局部变量 this 。
- 00 00
这样就结束了getTitle
方法,我们可以开始第三个方法public void setTitle(String title)
- 00 01 pubic
- 00 14 : #20 = Utf8 setTitle
- 00 15 : (Ljava/lang/String;)V 返回值为 void 接收一个 String 对象作为参数
- 00 01 : 方法的属性
- 00 0D : 方法属性为 Code
- 00 00 00 3E : 62 字节代表 code 对应字节码
- 00 02 : 最大操作栈数
- 00 02 :局部变量个数
- 00 00 00 06:方法执行字节码
2A 2B B5 00 03 B1
-
2A(aload_0)
-
2B(aloda_1)
-
B5(putfield) 参数 03 赋值给 title
-
B1(return)
-
00 00
-
00 02
-
00 0E 行号表
-
00 00 00 0A 向后数 10 个字节
00 02 00 00 00 0C 00 05 00 0D
有两个对应关系
- 00 0F :局部变量表
- 00 00 00 16:表示有 22 个字节表示局部变量表的信息
- 00 02 表示有两个局部变量
00 01 00 1A 00 00 00 02 00 1B
随后字节码可以按上面规则进行分析。
网友评论