javap 与字节码指令

来源:互联网 发布:查找淘宝用户购买记录 编辑:程序博客网 时间:2024/06/04 19:44

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_SUPERConstant 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类型到longfloat或者double类型long类型到floatdouble类型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(当返回值是booleanbytecharshortint类型时使用)、lreturn、freturn、dreturn和areturn,另外还有一条return指令供声明为void的方法、实例初始化方法、类和接口的类初始化方法使用

抛出异常指令:

athrow       

备注:
在非静态方法中,aload_0 表示将this 加载到操作数栈
在static 方法中,aload_0表示将方法中地第一个参数(局部变量表中的第一位),加载到操作数栈中。

参考:
http://www.yangyong.me/java-class%E6%96%87%E4%BB%B6%E5%92%8C%E8%99%9A%E6%8B%9F%E6%9C%BA%E5%AD%97%E8%8A%82%E7%A0%81%E6%8C%87%E4%BB%A4-%E5%A6%82%E4%BD%95%E6%9F%A5%E7%9C%8Bclass%E6%96%87%E4%BB%B6/

http://blog.csdn.net/congwiny/article/details/18867981

http://hubingforever.blog.163.com/blog/static/17104057920117822653653

http://www.itluobo.com/2016/04/20/bytecode/

jvm 栈讲解:
http://blog.csdn.net/a616413086/article/details/51272309
http://www.sohu.com/a/147500099_467808

原创粉丝点击