使用javap工具分析Java源代码

 javap [options] classfile

 可选 options
 -l               显示行号(源代码行与class中指令偏移量)和本地变量表
 -public          仅显示public的class及members  
 -protected       仅显示public和protected的class和member
 -private(-p)     显示所有的class和member
 -s               显示(方法和成员)internal type signatures
 -sysinfo         显示待处理类的系统信息(path, size, date, MD5 hash)
 -constants       显示常量(static final)
 -c               打印反编译代码
 -verbose         打印操作数栈大小,本地变量数量,方法参数的数量
 -classpath       javap操作的类所在的路径
 -bootclasspath
 -extdir

带分析class文件对应的Java源文件

AnaTool.java
public class AnaTool {
  private String name;
  String code = "001";
  protected String step;
  public String status;
  public static final String sys = "";

  public void p0(String type, int size){
    size += 5;
    System.out.println(size);
  }
  private void p1() {

  }
  void p2() {
  }
}

javap -s AnaTool

E:\>javap -s AnaTool
Compiled from "AnaTool.java"
public class AnaTool {
  java.lang.String code;
    descriptor: Ljava/lang/String;
  protected java.lang.String step;
    descriptor: Ljava/lang/String;
  public java.lang.String status;
    descriptor: Ljava/lang/String;
  public static final java.lang.String sys;
    descriptor: Ljava/lang/String;
  public AnaTool();
    descriptor: ()V

  public void p0(java.lang.String, int);
    descriptor: (Ljava/lang/String;I)V

  void p2();
    descriptor: ()V
}

javap -sysinfo AnaTool

E:\>javap -sysinfo AnaTool
Classfile /E:/AnaTool.class
  Last modified 2016-5-30; size 898 bytes
  MD5 checksum cbf392524f148a7429ef56eb943bff7d
  Compiled from "AnaTool.java"
public class AnaTool {
  java.lang.String code;
  protected java.lang.String step;
  public java.lang.String status;
  public static final java.lang.String sys;
  public AnaTool();
  public void p0(java.lang.String, int);
  void p2();
}

javap -public AnaTool

E:\>javap -public AnaTool
Compiled from "AnaTool.java"
public class AnaTool {
  public java.lang.String status;
  public static final java.lang.String sys;
  public AnaTool();
  public void p0(java.lang.String, int);
}

javap -protected AnaTool

E:\>javap -protected AnaTool
Compiled from "AnaTool.java"
public class AnaTool {
  protected java.lang.String step;
  public java.lang.String status;
  public static final java.lang.String sys;
  public AnaTool();
  public void p0(java.lang.String, int);
}

javap -private AnaTool

E:\>javap -private AnaTool
Compiled from "AnaTool.java"
public class AnaTool {
  private java.lang.String name;
  java.lang.String code;
  protected java.lang.String step;
  public java.lang.String status;
  public static final java.lang.String sys;
  public AnaTool();
  public void p0(java.lang.String, int);
  private void p1();
  void p2();
}

javap -constants AnaTool

E:\>javap -constants AnaTool
Compiled from "AnaTool.java"
public class AnaTool {
  java.lang.String code;
  protected java.lang.String step;
  public java.lang.String status;
  public static final java.lang.String sys = "";
  public AnaTool();
  public void p0(java.lang.String, int);
  void p2();
}

javap -c AnaTool

E:\>javap -c AnaTool
Compiled from "AnaTool.java"
public class AnaTool {
  java.lang.String code;

  protected java.lang.String step;

  public java.lang.String status;

  public static final java.lang.String sys;

  // 由编译器创建的默认构造函数
  public AnaTool();
    Code:
       0: aload_0
       1: invokespecial #1             // Method java/lang/Object."<init>":()V
       // 把源代码中成员的赋值语句(语法糖)编译成字节码并放到构造函数里
       4: aload_0
       5: ldc           #2             // String 001
       7: putfield      #3             // Field code:Ljava/lang/String;
      10: return

  public void p0(java.lang.String, int);
    Code:
       0: iinc          2, 5
       3: getstatic     #4             // Field java/lang/System.out:Ljava/io/PrintStream;
       6: iload_2
       7: invokevirtual #5             // Method java/io/PrintStream.println:(I)V
      10: return

  void p2();
    Code:
       0: return

}

javap -l AnaTool

E:\>javap -l AnaTool
Compiled from "AnaTool.java"
public class AnaTool {
  java.lang.String code;

  protected java.lang.String step;

  public java.lang.String status;

  public static final java.lang.String sys;

  public AnaTool();
    LineNumberTable:
      line 1: 0
      line 3: 4

  public void p0(java.lang.String, int);
    LineNumberTable:
      line 9: 0
      line 10: 3
      line 11: 10

  void p2();
    LineNumberTable:
      line 16: 0
}

我们以p0方法为例:

 源代码:
  public void p0(String type, int size){
    size += 5;                 //(line 9)
    System.out.println(size);  //(line 10)
  }

javap -l 显示行号与字节码偏移对应关系:

  public void p0(java.lang.String, int);
    LineNumberTable:
      line 9: 0        // 从偏移位置0开始
      line 10: 3       // 从偏移位置3开始
      line 11: 10      // 从偏移位置10开始(编译器生成的一个return指令)

我们看 javap -c 打印信息更加详细:

  public void p0(java.lang.String, int);
    Code:
      0: iinc          2, 5
      3: getstatic     #4  // Field java/lang/System.out:Ljava/io/PrintStream;
      6: iload_2
      7: invokevirtual #5  // Method java/io/PrintStream.println:(I)V
     10: return

方法中的第一行代码(在源代码文件中是第9行)size += 5;编译后为1条虚拟机指令:iinc 2, 5。从偏移位置(相对于方法)0开始,字节码指令 iinc占一个字节,参数2(代表本地变量2)占1个字节,参数5(常量值5)占一个字节。该行代码总共占3个字节。

所以第二行代码(在源代码文件中是第10行)System.out.println(size);从偏移位置3开始。字节码指令getstatic占1个字节,参数占2个字节(getstatic #indexbyte1 #indexbyte2),这里的参数由#4表示;iload_2指令占1个字节;invokevirtual指令占1个字节,参数占2个字节(invokevirtual #indexbyte1 #indexbyte2),这里的参数由#5表示。该行代码总共占7个字节。

所以最后由编译器生成的 return 指令从偏移位置10开始。

这里由一点需要注意,两个参数的位置由 #4 和 #5表示,这两个值可以在运行时常量池中找到(可以通过 javap -verbose 查看)。

通过javap -verbose指令我们可以看到:

#4 是一个 Fieldref(System类的out成员,类型为java.io.PrintStream)。#4又引用到#38#39#38正好引用到System类(#49为字符串表示);#39又间接引用到#50, #51#50为实例对象out的字符串名称,#51为引用到的PrintStream类的字符串表示。

#5是一个 MethodRef(PrintStream的println方法)。#5又引用到#40, #41#40正好引用到PrintStream类(#52为字符串表示);而#41又间接引用到#53, #54#53引用实例方法println的字符串表示,#54指向(I)V,表示参数是int,返回值为void。

PrintStream的println方法重载多个(参数不一样),#5[#40[#52], #41[#53, #54]]表示我们使用的是PrintStream类的输入参数为int,返回值为void的println方法。

javap -verbose AnaTool

E:\>javap -verbose AnaTool
Classfile /E:/AnaTool.class
  Last modified 2016-5-30; size 913 bytes
  MD5 checksum 0c08677ba3dafa2dd3d94eebe9e2d52c
  Compiled from "AnaTool.java"
public class AnaTool
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #12.#35        // java/lang/Object."<init>":()V
   #2 = String             #36            // 001
   #3 = Fieldref           #11.#37        // AnaTool.code:Ljava/lang/String;
   #4 = Fieldref           #38.#39        // java/lang/System.out:Ljava/io/PrintStream;
   #5 = Methodref          #40.#41        // java/io/PrintStream.println:(I)V
   #6 = Methodref          #42.#43        // java/lang/Thread.currentThread:()Ljava/lang/Thread;
   #7 = Long               1000l
   #9 = Methodref          #42.#44        // java/lang/Thread.sleep:(J)V
  #10 = Class              #45            // java/lang/Exception
  #11 = Class              #46            // AnaTool
  #12 = Class              #47            // java/lang/Object
  #13 = Utf8               name
  #14 = Utf8               Ljava/lang/String;
  #15 = Utf8               code
  #16 = Utf8               step
  #17 = Utf8               status
  #18 = Utf8               sys
  #19 = Utf8               ConstantValue
  #20 = String             #48            //
  #21 = Utf8               <init>
  #22 = Utf8               ()V
  #23 = Utf8               Code
  #24 = Utf8               LineNumberTable
  #25 = Utf8               p0
  #26 = Utf8               (Ljava/lang/String;I)V
  #27 = Utf8               p1
  #28 = Utf8               p2
  #29 = Utf8               main
  #30 = Utf8               ([Ljava/lang/String;)V
  #31 = Utf8               StackMapTable
  #32 = Class              #45            // java/lang/Exception
  #33 = Utf8               SourceFile
  #34 = Utf8               AnaTool.java
  #35 = NameAndType        #21:#22        // "<init>":()V
  #36 = Utf8               001
  #37 = NameAndType        #15:#14        // code:Ljava/lang/String;
  #38 = Class              #49            // java/lang/System
  #39 = NameAndType        #50:#51        // out:Ljava/io/PrintStream;
  #40 = Class              #52            // java/io/PrintStream
  #41 = NameAndType        #53:#54        // println:(I)V
  #42 = Class              #55            // java/lang/Thread
  #43 = NameAndType        #56:#57        // currentThread:()Ljava/lang/Thread;
  #44 = NameAndType        #58:#59        // sleep:(J)V
  #45 = Utf8               java/lang/Exception
  #46 = Utf8               AnaTool
  #47 = Utf8               java/lang/Object
  #48 = Utf8
  #49 = Utf8               java/lang/System
  #50 = Utf8               out
  #51 = Utf8               Ljava/io/PrintStream;
  #52 = Utf8               java/io/PrintStream
  #53 = Utf8               println
  #54 = Utf8               (I)V
  #55 = Utf8               java/lang/Thread
  #56 = Utf8               currentThread
  #57 = Utf8               ()Ljava/lang/Thread;
  #58 = Utf8               sleep
  #59 = Utf8               (J)V
{
  java.lang.String code;
    descriptor: Ljava/lang/String;
    flags:

  protected java.lang.String step;
    descriptor: Ljava/lang/String;
    flags: ACC_PROTECTED

  public java.lang.String status;
    descriptor: Ljava/lang/String;
    flags: ACC_PUBLIC

  public static final java.lang.String sys;
    descriptor: Ljava/lang/String;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
    ConstantValue: String

  public AnaTool();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: ldc           #2                  // String 001
         7: putfield      #3                  // Field code:Ljava/lang/String;
        10: return
      LineNumberTable:
        line 1: 0
        line 3: 4

  public void p0(java.lang.String, int);
    descriptor: (Ljava/lang/String;I)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=3
         0: iinc          2, 5
         3: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
         6: iload_2
         7: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        10: return
      LineNumberTable:
        line 9: 0
        line 10: 3
        line 11: 10

  void p2();
    descriptor: ()V
    flags:
    Code:
      stack=0, locals=1, args_size=1
         0: return
      LineNumberTable:
        line 16: 0
}
SourceFile: "AnaTool.java"

results matching ""

    No results matching ""