现在Java反编译工具或者插件非常多,也非常好用。比如我用的比较多得jd-gui。所以我们可能很少有机会使用到Javap命令。
这里我简单介绍下Javap,带各位入个门。介绍下这个命令不是使用它进行反编译,而是查看java编译器为我们生成 的字节码,通过比较字节码和源代码,我们可以发现很多的问题,一个很重要的作用就是了解很多编译器内部的工作机制。
下面我们通过具体的一个例子来简单的讲讲这个工具的作用,你不需要很深入的使用,这个简单的介绍和简单的使用就可以使你受益非浅。
首先我们先写一个非常简单的Java源文件:
class StringTest { public static void main(String[] args) { int i = 2; int j = 3; } }使用Javac 命令进行编译:
javac -g StringTest.java最终有两个文件:
user ~/csdn_test/session1$ls -l total 16 -rw-r--r-- 1 user staff 417 4 7 21:54 StringTest.class -rw-r--r-- 1 user staff 99 4 7 21:53 StringTest.java
下面我们分2步来看看javap的显示结果:
1.不带任何参数使用javap StringTest
这里我们可以看到的信息有,从哪个文件(StringTest.java)编译过来的。类里面调用两个方法,一个是默认的构造函数,一个是main方法。在没有显式声明构造方法时,会产生一个默认构造方法。这也验证了,为什么一个对象,默认总是先执行构造函数,特别是在继承的场合下,使用这个命令就可以看的很清楚了。
2.使用-c参数javap -c StringTest
带-p参数将额外的打印字节码信息。前面的和不带参数的输出一样,后面的显示了方法的具体的字节码,从这个输出里面我们又可以了解更多的内容。
首先是编译器生成的的缺省构造方法的内容为调用父类的构造方法super(), main()方法的字节码信息的内容这里简单解释下:
Code: 0: iconst_2 //把2放到栈顶 1: istore_1 //把栈顶的值放到局部变量1中,即i中 2: iconst_3 //把3放到栈顶 3: istore_2 //把栈顶的值放到局部变量1中,即j中 4: return所以再根据开始的java源码对照,对于 int i = 2;首先它会在栈中创建一个变量为i的引用,然后查找有没有字面值为2的地址,没找到,就开辟一个存放2这个字面值的地址,然后将i指向2的地址。j也是类似的。
延伸学习:
1、如果将main中的变量换成String 类型的,然后看看javap的结果。
比如:
String a = "a";
String b = "b";
String ab = "ab";
String ab1 = a + b;
String ab2 = "a" + "b"
2、使用更多的参数分析其结果,如javap -l xxx javap -p xxx(提示 -p会显示private相关的)
这几个参数几乎就可以构成javap的最常使用的集合,最常用的应该还是-c选项,因为可以打印字节码的信息,关于这些字节码的详细涵义在Java 虚拟机规范中定义,感兴趣的可以自己去找找相关资料。