字节码内部指令
java代码,以下代码在实际文件中,在9行到13行
public static void main(String[] args) {
LocalVariablesTest test = new LocalVariablesTest();
int num = 10;
test.test1();
}
javap命令反编译字节码文件
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: new #3 // class test3/LocalVariablesTest
3: dup
4: invokespecial #4 // Method "<init>":()V
7: astore_1
8: bipush 10
10: istore_2
11: aload_1
12: invokevirtual #5 // Method test1:()V
15: return
LineNumberTable:
line 10: 0
line 11: 8
line 12: 11
line 13: 15
LocalVariableTable:
Start Length Slot Name Signature
0 16 0 args [Ljava/lang/String;
8 8 1 test Ltest3/LocalVariablesTest;
11 5 2 num I
jclasslib概述
方法名称为main方法
方法入参是一个一维字符串数组,L代表是一个引用对象,V代表返回值为void
([Ljava/lang/String;)V 是JNI字段描述符
返回标识是public static 对应的16进制就是0x0009
Bytecode是字节码指令,和javap返回的指令一致
Exception Table 异常表
Misc 杂项
Maximum stack size: 最大操作数栈大小
Maximum local variables: 局部变量表最大长度
Code length: 字节码指令长度(对应字节码指令0到15 )
行号对应表
java代码的行号与程序计数器行号的对应关系
局部变量表
Start PC 对应程序计数器的行号
Length 对应程序计数器指令地址的作用域
可以同过
行号对应表
和源代码行号对照,Length就是每个变量在源码中的最大范围Start PC + Line Number均等于Code Length
Index 下标
Name 参数名称
Descriptor 描述
执行解析1
public class OperandStackTest {
public void testAddOperation() {
byte i = 15;
int j = 8;
int k = i + j;
}
}
通过javap -v命令将反编译字节码文件
操作数栈最大长度2,局部变量表最大长度4
public void testAddOperation();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=4, args_size=1
0: bipush 15
2: istore_1
3: bipush 8
5: istore_2
6: iload_1
7: iload_2
8: iadd
9: istore_3
10: return
bipush 15
byte类型会被识别为int,并在操作数栈中压入int类型的15
istore_1
将操作数栈的15弹出,并放入局部变量表索引1的位置
bipush 8
在操作数栈中压入int类型的8
istore_2
将操作数栈的8弹出,并放入局部变量表索引2的位置
iload_1
获取局部变量表中索引1的位置,并压入操作数栈中
iload_2
获取局部变量表中索引2的位置,并压入操作数栈中
iadd
操作数栈中的8和15依次出栈,计算为23后压入操作数栈中
istore_3
将23出栈,并放入局部变量表中索引3的位置
return
方法结束,整个栈帧从虚拟机栈中弹出
执行解析2
public class MethodAreaDemo {
public static void main(String[] args) {
int x = 500;
int y = 100;
int a = x / y;
int b = 50;
System.out.println(a + b);
}
}
通过javap指令转换,关键内容截取
// 常量池部分
Constant pool:
#1 = Methodref #5.#24 // java/lang/Object."<init>":()V
#2 = Fieldref #25.#26 // java/lang/System.out:Ljava/io/PrintStream;
#3 = Methodref #27.#28 // java/io/PrintStream.println:(I)V
#25 = Class #31 // java/lang/System
#26 = NameAndType #32:#33 // out:Ljava/io/PrintStream;
#31 = Utf8 java/lang/System
#32 = Utf8 out
#33 = Utf8 Ljava/io/PrintStream;
// 方法部分
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=5, args_size=1
0: sipush 500
3: istore_1
4: bipush 100
6: istore_2
7: iload_1
8: iload_2
9: idiv
10: istore_3
11: bipush 50
13: istore 4
15: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
18: iload_3
19: iload 4
21: iadd
22: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
25: return
sipush 500
将500压入操作数栈中
istore_1
将操作数栈中的500弹出,并放入局部变量表索引1的位置
bipush 100
将100压入操作数栈中
istore_2
存入本地变量表中
iload_1
将局部变量表下标1的位置取出,压入操作数栈中
iload_2
将局部变量表下标2的位置取出,压入操作数栈中
idiv
将操作数栈中的数据依次去除,后者除以前者,结果压入操作数栈中
istore_3
将操作数栈中的5弹出,存入本地变量表中
bipush 50
将50压入操作数栈中
istore 4
50弹出操作数栈,放入局部变量表中
getstatic #2
从常量池中取出#2,压入操作数栈中
iload_3
将操作数栈下标3的元素去除,压入操作数栈中
iload 4
将操作数栈下标4的元素压入操作数栈中
iadd
将操作数栈50和5弹出,相加后压入操作数栈
invokevirtual #3
弹出#2调用#3(println方法),控制台输出55
return
执行结束return,操作数栈弹出