javap 是 jdk 默认的一个工具,在 jdk 安装目录的 bin 文件夹下。通过该工具可以查看 java 编译器为我们生成的字节码,通过比较字节码和源代码来了解很多编译器内部的工作机制。
javap 的标准输出是公有变量和类的成员函数。 javap 反汇编器的命令行使用如下:
用法: javap < 选项功能 > < 类 > ...
详细用法可以通过 javap –help 来查看。
下面将通过简单的 helloworld 程序使用 javap 工具来加深认识,程序源代码如下:
package pak1;
public class Test1 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1 = "Hello World" ;
System. out .println(s1);
}
}
1 、 javap Test1
Compiled from "Test1.java"
public class pak1.Test1 extends java.lang.Object{
public pak1.Test1();
public static void main(java.lang.String[]);
}
从上述结果中我们可以看出,如果类没有显示的从其它类派生那么它就是从 Object 派生。如果没有为类显示的申明构造方法,那么编译器将为之生成一个缺省构造方法(不带参数的构造方法)。
2 、 javap -c Test1
Compiled from "Test1.java"
public class pak1.Test1 extends java.lang.Object{
public pak1.Test1();
Code:
0: aload_0
1: invokespecial #8; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #16; //String Hello World
2: astore_1
3: getstatic #18; //Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_1
7: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
10: return
}
-c 参数表示反汇编代码。
该命令显示了方法的具体的字节码,关于这些字节码的详细涵义在 Java 虚拟机规范中定义。例如 main() 方法中 ldc 表示压入常数池中的项 s1 。
3 、 javap -l test1
Compiled from "Test1.java"
public class pak1.Test1 extends java.lang.Object{
public pak1.Test1();
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lpak1/Test1;
public static void main(java.lang.String[]);
LineNumberTable:
line 10: 0
line 11: 3
line 12: 10
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 args [Ljava/lang/String;
3 8 1 s1 Ljava/lang/String;
}
-l 参数将显示行号和局部变量表。
从上面的输出中我们可以得到方法中的变量和方法的源代码对于字节码信息的,例如对应 main() 方法,它的变量为输入参数 args 以及局部变量 s1 ,方法的源代码的第 10 行对应字节码的第 0 个偏移量,第 11 行对应字节码的第 3 个偏移量,而第 12 行对应字节码的第 10 偏移量(参看 javap -c 的输出前面的偏移量),第 12 行实际是没有语句的,但是有一个隐含的 return ,而偏移量 10 实际对应的也是 return 调用。
4 、 javap -p test1
Compiled from "Test1.java"
public class pak1.Test1 extends java.lang.Object{
public pak1.Test1();
public static void main(java.lang.String[]);
}
-p 参数将额外的打印 private 成员和方法的信息,因为这个类没有因此输出相同。