D:/test>javap -help
Usage: javap <options> <classes>...
where options include:
-c Disassemble the code
-classpath <pathlist> Specify where to find user class files
-extdirs <dirs> Override location of installed extensions
-help Print this usage message
-J<flag> Pass <flag> directly to the runtime system
-l Print line number and local variable tables
-public Show only public classes and members
-protected Show protected/public classes and members
-package Show package/protected/public classes and members (default)
-private Show all classes and members
-s Print internal type signatures
-bootclasspath <pathlist> Override location of class files loaded by the bootstrap class loader
-verbose Print stack size, number of locals and args for methods If verifying, print reasons for failure
我平时一般用c选项用得比较多,该命令用于列出每个方法所执行的JVM指令,并显示每个方法的字节码的实际作用。
我们写个HelloWorld的程序来测试一下该命令。
public class HelloWorld {
public static void main(String[] args){
System.out.println("Hello World!");
}
}
然后在命令行将其编译,生成HelloWorld.class文件。
接着我们输入javap -c HelloWorld >> disa.txt
“>> disa.txt”意思是重定向输出流,将所生成的信息输出到disa.txt文本文件中。其内容如下:
Compiled from "HelloWorld.java"
public class HelloWorld extends java.lang.Object{
public HelloWorld();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String Hello World!
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/Str
ing;)V
8: return
}
我们对main方法下面几行进行解释:
这几行用于转换Java语言中的代码行System.out.println("Hello World!");
第一个指令getstatic从java.lang.system对象的out字段中检索PrintStream对象,并放到操作数栈中。第二行的ldc 将字符串"Hello World!"压到操作数栈中。最后,invokevirtual执行java.io.PrintStream类中的println方法。该方法的正确执 行要求操作数栈中存在一个String以及java.io.PrintStream类的一个实例,并依次排列。---------------------------------------------------------------------------------------------------------------
用javap 反汇编帮你理解java特性 (使用 javap 深入查看类文件)
作者: Builder.com
使用 javap 深入查看类文件
Java 开发人员熟悉在一个循环中使用StringBuffer 来代替串联 String 对象能获得最佳性能。然而,多数开发人员从来没有比较两种方法产生的字节代码的区别。在 Java 开发工具包(JDK)中有一个叫做 javap 的工具可以告诉你为什么这样做可以获得最佳性能。
Javap 将一个类和它的方法的一些转储信息输出到标准输出。该工具不把代码反编译为 java 源代码,但是它会把字节代码反汇编成为由 Java 虚拟机规范定义的字节代码指令。
在你需要查看编译器为你或者给你做了什么的时候,或者你想要看一处代码的改动对编译后的类文件有什么影响的时候,javap 相当有用。
现在以我们前面提到的 StringBuffer 和 String 作为一个例子。下面是一个专门为例子设计的类,它有两个方法,都返回一个由0到 n 的数字组成的 String,其中 n 由调用者提供。两个方法唯一的区别在于一个使用 String 构建结果,另外一个使用 StringBuffer 构建结果。
public class JavapTip {
public static void main(String []args) {
}
private static String withStrings(int count) {
String s = "";
for (int i = 0; i < count; i++) {
s += i;
}
return s;
}
private static String withStringBuffer(int count) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < count; i++) {
sb.append(i);
}
return sb.toString();
}
}
现在让我们看看对这个类使用–c 选项运行 javap 的输出。-c 选项告诉 javap 反汇编在类中遇到的字节代码。
运行方式如下:
>javap -c JavapTip
此命令的输出为:
Method java.lang.String withStrings(int)
0 ldc #2
2 astore_1
3 iconst_0
4 istore_2
5 goto 30
8 new #3
11 dup
12 invokespecial #4
15 aload_1
16 invokevirtual #5
19 iload_2
20 invokevirtual #6
23 invokevirtual #7
26 astore_1
27 iinc 2 1
30 iload_2
31 iload_0
32 if_icmplt 8
35 aload_1
36 areturn
Method java.lang.String withStringBuffer(int)
0 new #3
3 dup
4 invokespecial #4
7 astore_1
8 iconst_0
9 istore_2
10 goto 22
13 aload_1
14 iload_2
15 invokevirtual #6
18 pop
19 iinc 2 1
22 iload_2
23 iload_0
24 if_icmplt 13
27 aload_1
28 invokevirtual #7
31 areturn
如果你以前没有看过 Java 汇编器,那么这个输出对你来说就会比较难懂,但是你应该可以看到 withString 方法在每次循环的时候都新创建了一个 StringBuffer 实例。然后它将已有的 String 的当前值追加到 StringBuffer 上,然后追加循环的当前值。最后,它对 buffer 调用 toString 并将结果赋给现有的 String 引用。
withStringBuffer 方法与这个方法正好相反,在每次循环的时候 withStringBuffer 只调用现有 StringBuffer 的 append 方法,没有创建新的对象,也没有新的 String 引用。
在这种情况下,我们已经知道了使用 StringBuffer 代替 String 是一种好的做法,但是如果我们不知道呢?那么 javap 可以帮助我们找到答案。 在这里你可以看到更详细的关于String,StringBuffer 的解释
你并不会经常需要一个 Java 反汇编器,但是当你需要的时候,知道你自己的机器已经有一个并且用法相当简单的反汇编器当然是一件好事。如果你感兴趣,看书看看 javap 的其它选项——或许你会发现在你的环境中需要的特性。
--------------------------------------------------------------------------------
本文作者:David Petersheim是Genscape公司的一位应用开发主任。他设计和开发服务器端应用程序来获取和处理实时能源数据。