javap 常用指令
-help –help -? 输出此用法消息
-version 版本信息
-v -verbose 输出附加信息
-l 输出行号和本地变量表
-public 仅显示公共类和成员
-protected 显示受保护的/公共类和成员
-package 显示程序包/受保护的/公共类
和成员 (默认)
-p -private 显示所有类和成员
-c 对代码进行反汇编
-s 输出内部类型签名
-sysinfo 显示正在处理的类的
系统信息 (路径, 大小, 日期, MD5 散列)
-constants 显示静态最终常量
-classpath 指定查找用户类文件的位置
-bootclasspath 覆盖引导类文件的位置
反编译 class 字节码 javap -v class,例如:
class test{
int c;
int a;
public static void main(String args[]){
test t = new test();
t.get(5);
}
test(){
super();
c = 1;
a = 0;
}
public int get(int b){
a = b;
c = a;
return this.a;
}
}
使用javap -v 反编译字节码显示的为:
Last modified 2017-6-20; size 437 bytes
MD5 checksum a42a0734a405dcc441a98574b1ac0f69
Compiled from "test.java"
class test
SourceFile: "test.java"
minor version: 0
major version: 51
flags: ACC_SUPER
Constant pool:
#1 = Class #21 // test
#2 = Methodref #1.#22 // test."<init>":()V
#3 = Methodref #1.#23 // test.get:(I)I
#4 = Methodref #7.#22 // java/lang/Object."<init>":()V
#5 = Fieldref #1.#24 // test.c:I
#6 = Fieldref #1.#25 // test.a:I
#7 = Class #26 // java/lang/Object
#8 = Utf8 c
#9 = Utf8 I
#10 = Utf8 a
#11 = Utf8 main
#12 = Utf8 ([Ljava/lang/String;)V
#13 = Utf8 Code
#14 = Utf8 LineNumberTable
#15 = Utf8 <init>
#16 = Utf8 ()V
#17 = Utf8 get
#18 = Utf8 (I)I
#19 = Utf8 SourceFile
#20 = Utf8 test.java
#21 = Utf8 test
#22 = NameAndType #15:#16 // "<init>":()V
#23 = NameAndType #17:#18 // get:(I)I
#24 = NameAndType #8:#9 // c:I
#25 = NameAndType #10:#9 // a:I
#26 = Utf8 java/lang/Object
{
int c;
flags:
int a;
flags:
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: new #1 // class test //创建一个test 对象,并将其放入操作数栈中
3: dup // 复制刚刚放入的引用(栈中存在两个相同的引用),放入栈中
4: invokespecial #2 // Method "<init>":()V //使用栈顶的引用调用Constant pool中#2方法即 test 的构造方法,并将引用弹出
7: astore_1 // 将this引用保存到局部变量表 索引1 的位置,然后引出栈
8: aload_1 //将 局部变量表中 1 的值,压入栈中(即对应局部变量 t)
9: iconst_5 // 将5 压入栈中
10: invokevirtual #3 // Method get:(I)I //调用使用局部变量调用其get方法,并从栈顶 中取出 方法的参数
13: pop
14: return
LineNumberTable:
line 5: 0
line 6: 8
line 7: 14
test();
flags:
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #4 // Method java/lang/Object."<init>":()V //构造方法调用父类的super 方法,此处调用的是Object 空的构造方法
4: aload_0 //将局部变量中的第0位(this)加载到,栈中
5: iconst_1 //将1 压入栈顶
6: putfield #5 // Field c:I //将 1 赋值给c
9: aload_0 //将局部变量中的第0位(this)加载到,栈中
10: iconst_0 //将0 压入栈顶
11: putfield #6 // Field a:I //将 0 赋值给a
14: return
LineNumberTable:
line 9: 0
line 10: 4
line 11: 9
line 12: 14
public int get(int);
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0 //aload_0 局部变量中的第0位一般为 this,见备注
1: iload_1 //取出局部变量中 的第1位(int类型),压入栈中
2: putfield #6 // Field a:I //将 第一个局部变量赋值给 a
5: aload_0
6: aload_0
7: getfield #6 // Field a:I //获取this.a 的值,并将其压入栈中
10: putfield #5 // Field c:I //将this.a 赋值给 this.c
13: aload_0
14: getfield #6 // Field a:I //获取this.a 的值,并将其压入栈中
17: ireturn //返回this.a
LineNumberTable:
line 14: 0
line 15: 5
line 16: 13
}
这个class文件包含三个主要内容:
- Constant Pool 包含当前类的符号
- Method 主要包含
- 方法签名和访问标识
- 字节码
- LineNumberTable 包含源码到字节码的映射,供debug使用
- LocalVariableTable 包含当前frame里的local variable,这里只有一个this变量(这里没有输出来)。
其他常见的class字节码指令:
加载和存储指令:
将一个局部变量加载到操作栈的指令包括有:iload、iload_<n>、lload、lload_<n>、fload、fload_<n>、dload、dload_<n>、aload、aload_<n>
将一个数值从操作数栈存储到局部变量表的指令包括有:istore、istore_<n>、lstore、lstore_<n>、fstore、fstore_<n>、dstore、dstore_<n>、astore、astore_<n>
将一个常量加载到操作数栈的指令包括有:bipush、sipush、ldc、ldc_w、ldc2_w、aconst_null、iconst_m1、iconst_<i>、lconst_<l>、fconst_<f>、dconst_<d>
扩充局部变量表的访问索引的指令:wide
运算指令:
加法指令:iadd、ladd、fadd、dadd
减法指令:isub、lsub、fsub、dsub
乘法指令:imul、lmul、fmul、dmul
除法指令:idiv、ldiv、fdiv、ddiv
求余指令:irem、lrem、frem、drem
取反指令:ineg、lneg、fneg、dneg
位移指令:ishl、ishr、iushr、lshl、lshr、lushr
按位或指令:ior、lor
按位与指令:iand、land
按位异或指令:ixor、lxor
局部变量自增指令:iinc
比较指令:dcmpg、dcmpl、fcmpg、fcmpl、lcmp
类型转换指令:
Java虚拟机对于宽化类型转换直接支持,并不需要指令执行,包括:
int类型到long、float或者double类型
long类型到float、double类型
float类型到double类型
窄化类型转换指令包括有:i2b、i2c、i2s、l2i、f2i、f2l、d2i、d2l和d2f。但是窄化类型转换很可能会造成精度丢失。
对象创建与操作指令:
创建类实例的指令:new
创建数组的指令:newarray,anewarray,multianewarray
访问类字段(static字段,或者称为类变量)和实例字段(非static字段,或者成为实例变量)的指令:getfield、putfield、getstatic、putstatic
把一个数组元素加载到操作数栈的指令:baload、caload、saload、iaload、laload、faload、daload、aaload
将一个操作数栈的值储存到数组元素中的指令:bastore、castore、sastore、iastore、fastore、dastore、aastore
取数组长度的指令:arraylength
检查类实例类型的指令:instanceof、checkcast
操作数栈管理指令:
Java虚拟机提供了一些用于直接操作操作数栈的指令,包括:pop、pop2、dup、dup2、dup_x1、dup2_x1、dup_x2、dup2_x2和swap;
控制转移指令:
条件分支:ifeq、iflt、ifle、ifne、ifgt、ifge、ifnull、ifnonnull、if_icmpeq、if_icmpne、if_icmplt, if_icmpgt、if_icmple、if_icmpge、if_acmpeq和if_acmpne。
复合条件分支:tableswitch、lookupswitch
无条件分支:goto、goto_w、jsr、jsr_w、ret
方法调用和返回指令:
invokevirtual指令用于调用对象的实例方法,根据对象的实际类型进行分派(虚方法分派),这也是Java语言中最常见的方法分派方式。
invokeinterface指令用于调用接口方法,它会在运行时搜索一个实现了这个接口方法的对象,找出适合的方法进行调用。
invokespecial指令用于调用一些需要特殊处理的实例方法,包括实例初始化方法(§2.9)、私有方法和父类方法。
invokestatic指令用于调用类方法(static方法)。
而方法返回指令则是根据返回值的类型区分的,包括有ireturn(当返回值是boolean、byte、char、short和int类型时使用)、lreturn、freturn、dreturn和areturn,另外还有一条return指令供声明为void的方法、实例初始化方法、类和接口的类初始化方法使用
抛出异常指令:
athrow
备注:
在非静态方法中,aload_0 表示将this 加载到操作数栈
在static 方法中,aload_0表示将方法中地第一个参数(局部变量表中的第一位),加载到操作数栈中。
http://blog.youkuaiyun.com/congwiny/article/details/18867981
http://hubingforever.blog.163.com/blog/static/17104057920117822653653
http://www.itluobo.com/2016/04/20/bytecode/
jvm 栈讲解:
http://blog.youkuaiyun.com/a616413086/article/details/51272309
http://www.sohu.com/a/147500099_467808