你的位置:首页 > Java教程

[Java教程]说说javap命令


javap定义

javap是 Java class文件分解器,可以反编译(即对javac编译的文件进行反编译),也可以查看java编译器生成的字节码。用于分解class文件。

测试类

public class JavapTest {  private static final int _P_1 = 1;  public static final int _P_2 = 2;  public static void main(String[] args) {    int m = 0, n = 0;    for (int i = 0; i < 10; i++) {      m = m++;      n = ++n;    }    System.out.println("m = " + m);    System.out.println("n = " + n);  }}

javap命令参数

C:\>javap -help用法: javap <options> <classes>其中, 可能的选项包括: -help --help -?    输出此用法消息 -version         版本信息 -v -verbose       输出附加信息 -l            输出行号和本地变量表 -public         仅显示公共类和成员 -protected        显示受保护的/公共类和成员 -package         显示程序包/受保护的/公共类              和成员 (默认) -p -private       显示所有类和成员 -c            对代码进行反汇编 -s            输出内部类型签名 -sysinfo         显示正在处理的类的              系统信息 (路径, 大小, 日期, MD5 散列) -constants        显示静态最终常量 -classpath <path>    指定查找用户类文件的位置 -bootclasspath <path>  覆盖引导类文件的位置

javap -version

C:\>javap -version1.7.0_71显示java版本

javap -p

C:\Users\user\Desktop>javap -p JavapTest.classCompiled from "JavapTest.java"public class com.method.handler.JavapTest { private static final int _P_1; public static final int _P_2; public com.method.handler.JavapTest(); public static void main(java.lang.String[]); private void say();}显示类所有可访问修饰符范围》private的成员

javap -public

C:\Users\user\Desktop>javap -public JavapTest.classCompiled from "JavapTest.java"public class com.method.handler.JavapTest { public static final int _P_2; public com.method.handler.JavapTest(); public static void main(java.lang.String[]);}显示类的public成员

javap -protected

C:\Users\user\Desktop>javap -protected JavapTest.classCompiled from "JavapTest.java"public class com.method.handler.JavapTest { public static final int _P_2; public com.method.handler.JavapTest(); public static void main(java.lang.String[]);}显示类所有可访问修饰符范围》protected的成员

javap -l

C:\Users\user\Desktop>javap -p -l JavapTest.classCompiled from "JavapTest.java"public class com.method.handler.JavapTest { private static final int _P_1; public static final int _P_2; public com.method.handler.JavapTest();  LineNumberTable:   line 6: 0 public static void main(java.lang.String[]);  LineNumberTable:   line 12: 0   line 13: 4   line 14: 12   line 15: 17   line 13: 22   line 17: 28   line 18: 53   line 19: 78 private void say();  LineNumberTable:   line 23: 0   line 24: 8}输出行号和本地变量表?看的不是很明白

javap -package

C:\Users\user\Desktop>javap -package JavapTest.classCompiled from "JavapTest.java"public class com.method.handler.JavapTest { public static final int _P_2; public com.method.handler.JavapTest(); public static void main(java.lang.String[]);}与javap -public作用类似

javap -v/-p -v

C:\Users\user\Desktop>javap -p -v JavapTest.classClassfile /C:/Users/frinder_liu/Desktop/JavapTest.class Last modified 2016-4-27; size 911 bytes MD5 checksum e903be7495f5c462d6459a792e063628 Compiled from "JavapTest.java"public class com.method.handler.JavapTest SourceFile: "JavapTest.java" minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPERConstant pool:  #1 = Methodref     #13.#30    // java/lang/Object."<init>":()V  #2 = Fieldref      #31.#32    // java/lang/System.out:Ljava/io/PrintStream;  #3 = Class       #33      // java/lang/StringBuilder  #4 = Methodref     #3.#30     // java/lang/StringBuilder."<init>":()V  #5 = String       #34      // m =  #6 = Methodref     #3.#35     // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;  #7 = Methodref     #3.#36     // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;  #8 = Methodref     #3.#37     // java/lang/StringBuilder.toString:()Ljava/lang/String;  #9 = Methodref     #38.#39    // java/io/PrintStream.println:(Ljava/lang/String;)V #10 = String       #40      // n = #11 = String       #41      // hello world... #12 = Class       #42      // com/method/handler/JavapTest #13 = Class       #43      // java/lang/Object #14 = Utf8        _P_1 #15 = Utf8        I #16 = Utf8        ConstantValue #17 = Integer      1 #18 = Utf8        _P_2 #19 = Integer      2 #20 = Utf8        <init> #21 = Utf8        ()V #22 = Utf8        Code #23 = Utf8        LineNumberTable #24 = Utf8        main #25 = Utf8        ([Ljava/lang/String;)V #26 = Utf8        StackMapTable #27 = Utf8        say #28 = Utf8        SourceFile #29 = Utf8        JavapTest.java #30 = NameAndType    #20:#21    // "<init>":()V #31 = Class       #44      // java/lang/System #32 = NameAndType    #45:#46    // out:Ljava/io/PrintStream; #33 = Utf8        java/lang/StringBuilder #34 = Utf8        m = #35 = NameAndType    #47:#48    // append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #36 = NameAndType    #47:#49    // append:(I)Ljava/lang/StringBuilder; #37 = NameAndType    #50:#51    // toString:()Ljava/lang/String; #38 = Class       #52      // java/io/PrintStream #39 = NameAndType    #53:#54    // println:(Ljava/lang/String;)V #40 = Utf8        n = #41 = Utf8        hello world... #42 = Utf8        com/method/handler/JavapTest #43 = Utf8        java/lang/Object #44 = Utf8        java/lang/System #45 = Utf8        out #46 = Utf8        Ljava/io/PrintStream; #47 = Utf8        append #48 = Utf8        (Ljava/lang/String;)Ljava/lang/StringBuilder; #49 = Utf8        (I)Ljava/lang/StringBuilder; #50 = Utf8        toString #51 = Utf8        ()Ljava/lang/String; #52 = Utf8        java/io/PrintStream #53 = Utf8        println #54 = Utf8        (Ljava/lang/String;)V{ private static final int _P_1;  flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL  ConstantValue: int 1 public static final int _P_2;  flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL  ConstantValue: int 2 public com.method.handler.JavapTest();  flags: ACC_PUBLIC  Code:   stack=1, locals=1, args_size=1     0: aload_0     1: invokespecial #1         // Method java/lang/Object."<init>":()V     4: return   LineNumberTable:    line 6: 0 public static void main(java.lang.String[]);  flags: ACC_PUBLIC, ACC_STATIC  Code:   stack=3, locals=4, args_size=1     0: iconst_0     1: istore_1     2: iconst_0     3: istore_2     4: iconst_0     5: istore_3     6: iload_3     7: bipush    10     9: if_icmpge   28    12: iload_1    13: iinc     1, 1    16: istore_1    17: iinc     2, 1    20: iload_2    21: istore_2    22: iinc     3, 1    25: goto     6    28: getstatic   #2         // Field java/lang/System.out:Ljava/io/PrintStream;    31: new      #3         // class java/lang/StringBuilder    34: dup    35: invokespecial #4         // Method java/lang/StringBuilder."<init>":()V    38: ldc      #5         // String m =    40: invokevirtual #6         // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;    43: iload_1    44: invokevirtual #7         // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;    47: invokevirtual #8         // Method java/lang/StringBuilder.toString:()Ljava/lang/String;    50: invokevirtual #9         // Method java/io/PrintStream.println:(Ljava/lang/String;)V    53: getstatic   #2         // Field java/lang/System.out:Ljava/io/PrintStream;    56: new      #3         // class java/lang/StringBuilder    59: dup    60: invokespecial #4         // Method java/lang/StringBuilder."<init>":()V    63: ldc      #10         // String n =    65: invokevirtual #6         // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;    68: iload_2    69: invokevirtual #7         // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;    72: invokevirtual #8         // Method java/lang/StringBuilder.toString:()Ljava/lang/String;    75: invokevirtual #9         // Method java/io/PrintStream.println:(Ljava/lang/String;)V    78: return   LineNumberTable:    line 12: 0    line 13: 4    line 14: 12    line 15: 17    line 13: 22    line 17: 28    line 18: 53    line 19: 78   StackMapTable: number_of_entries = 2      frame_type = 254 /* append */       offset_delta = 6    locals = [ int, int, int ]      frame_type = 250 /* chop */     offset_delta = 21 private void say();  flags: ACC_PRIVATE  Code:   stack=2, locals=1, args_size=1     0: getstatic   #2         // Field java/lang/System.out:Ljava/io/PrintStream;     3: ldc      #11         // String hello world...     5: invokevirtual #9         // Method java/io/PrintStream.println:(Ljava/lang/String;)V     8: return   LineNumberTable:    line 23: 0    line 24: 8}命令说明是:输出附加信息class文件的路径、最后修改时间、文件大小等类的全路径、源(java)文件等常量池常量定义、值构造方法程序调用及执行逻辑(这个涉及的内容就比较多了)总之,javap -v命令是很强大的一个命令!

javap -c

C:\Users\user\Desktop>javap -c JavapTest.classCompiled from "JavapTest.java"public class com.method.handler.JavapTest { public static final int _P_2; public com.method.handler.JavapTest();  Code:    0: aload_0    1: invokespecial #1         // Method java/lang/Object."<init>":()V    4: return public static void main(java.lang.String[]);  Code:    0: iconst_0    1: istore_1    2: iconst_0    3: istore_2    4: iconst_0    5: istore_3    6: iload_3    7: bipush    10    9: if_icmpge   28   12: iload_1   13: iinc     1, 1   16: istore_1   17: iinc     2, 1   20: iload_2   21: istore_2   22: iinc     3, 1   25: goto     6   28: getstatic   #2         // Field java/lang/System.out:Ljava/io/PrintStream;   31: new      #3         // class java/lang/StringBuilder   34: dup   35: invokespecial #4         // Method java/lang/StringBuilder."<init>":()V   38: ldc      #5         // String m =   40: invokevirtual #6         // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;   43: iload_1   44: invokevirtual #7         // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;   47: invokevirtual #8         // Method java/lang/StringBuilder.toString:()Ljava/lang/String;   50: invokevirtual #9         // Method java/io/PrintStream.println:(Ljava/lang/String;)V   53: getstatic   #2         // Field java/lang/System.out:Ljava/io/PrintStream;   56: new      #3         // class java/lang/StringBuilder   59: dup   60: invokespecial #4         // Method java/lang/StringBuilder."<init>":()V   63: ldc      #10         // String n =   65: invokevirtual #6         // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;   68: iload_2   69: invokevirtual #7         // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;   72: invokevirtual #8         // Method java/lang/StringBuilder.toString:()Ljava/lang/String;   75: invokevirtual #9         // Method java/io/PrintStream.println:(Ljava/lang/String;)V   78: return}其实,javap -c 输出内部javap -v中已经有了,我们详细介绍下javap -c命令的输出内容0: iconst_0 前面0:表示执行的顺序,iconst_0把值 0 放入栈顶,_0中的0代表压栈的值,如:iconst_5,即把5压入栈顶1: istore_1 将栈顶的值放入变量1 中,_1代表变量的序列,本例中为:m,如:istore_2即为变量n赋值6: iload_3 将变量3 即 i 的的值放入栈顶,与iconst不同的是,iload操作的值是已经定义好存在的值,iconst是定义时的压栈操作
13: iinc 1, 1 将变量1 的值加1

文章开头的demo中最终的结果是什么呢?

m = 0n = 10为什么呢?我们来关注下这几行:12: iload_1       -- 将变量1 值放入栈项13: iinc     1, 1 -- 将变量1 增加1 变为2,栈顶值仍然是1。其中第一个1 表示变量,第二个1 表示增量16: istore_1      -- 将栈顶值赋值给变量1,变量1 仍然为117: iinc     2, 1 -- 将变量2 增加1 变为2,栈顶值仍然是1。其中第一个2 表示变量,第二个1 表示增量20: iload_2       -- 将变量2 值放入栈顶21: istore_2      -- 将栈顶值赋值给变量2,变量2 值为2记住一个点:int m = 0, n = 0;m = m++; -- 会先将m值(即0)赋值给m后再++n = ++n; -- n先++后再把值赋值给n此时,m = 0, n = 1;

这个地方有点绕,需要多看几次,理顺逻辑与关系!

这里可以参考下http://blog.csdn.net/junsure2012/article/details/7099222,讲的很详细也易懂!

 

javap -s/-p -s

C:\Users\user\Desktop>javap -p -s JavapTest.classCompiled from "JavapTest.java"public class com.method.handler.JavapTest { private static final int _P_1;  Signature: I public static final int _P_2;  Signature: I public com.method.handler.JavapTest();  Signature: ()V public static void main(java.lang.String[]);  Signature: ([Ljava/lang/String;)V private void say();  Signature: ()V}输出内部类型签名

javap -sysinfo/-p -sysinfo

C:\Users\user\Desktop>javap -sysinfo JavapTest.classClassfile /C:/Users/user/Desktop/JavapTest.class Last modified 2016-4-27; size 911 bytes MD5 checksum 3f6dfcf7121785760b234224c5d135fd Compiled from "JavapTest.java"public class com.method.handler.JavapTest { public static final int _P_2; public com.method.handler.JavapTest(); public static void main(java.lang.String[]);}显示正在处理的类的系统信息 (路径, 大小, 日期, MD5 散列)

javap -constants/-p -constants

C:\Users\user\Desktop>javap -constants JavapTest.classCompiled from "JavapTest.java"public class com.method.handler.JavapTest { public static final int _P_2 = 2; public com.method.handler.JavapTest(); public static void main(java.lang.String[]);}显示静态最终常量

javap -classpath/-bootclasspath

先跳过