javap的使用

javap的使用
2013-04-11 08:56:12      我来说两句       作者:crocodile_songe
收藏     我要投稿

许我们很少会使用到javap工具,因为现在有很多好的反编译工具,但是我在此介绍这个工具不是使用它进行反编译,而是查看java编译器为我们生成 的字节码,通过比较字节码和源代码,我们可以发现很多的问题,一个很重要的作用就是了解很多编译器内部的工作机制。

public class Main {


    public static void main(String[] args) {
        String s = "abc";
        String ss = "ok"+s+"xyz"+5;
        System.out.println(ss);
    }
}


在反编译前你当然需要先编译这个类了:javac -g Main.java(使用-g参数是因为要得到下面javap -l时的输出需要使用此选项)
编译完成后,我们在使用不同的选项看看不同的效果:


1.先看看最简单的不带参数的情况:javap Main:

 \


 不带参数的情况将答应类的public信息,包括成员和方法
从上面的输出中我们确定了两个知识:如果类没有显示的从其它类派生那么它就是从Object派生;如果没有为类显示的申明构造方法,那么编译器将为之生成一个缺省构造方法(不带参数的构造方法)


2.javap -c Main

 

\
前面的和不带参数的输出一样,后面的显示了方法的具体的字节码,从这个输出里面我们又可以了解更多的内容.


从上面的代码很容易看出,虽然在源程序中使用了"+",但在编译时仍然将"+"转换成StringBuilder。因此,我们可以得出结论,在Java中无论使用何种方式进行字符串连接,实际上都使用的是StringBuilder类。

3.javap -l Main

 

\
-l参数将显示行号和局部变量表


4.javap -p Main

 \

 

 


 -p参数将额外的打印private成员和方法的信息,因为这个类没有因此输出相同

这几个参数几乎就可以构成javap的最常使用的集合,最常用的应该还是-c选项,因为可以打印字节码的信息,关于这些字节码的详细涵义在Java 虚拟机规范中定义,感兴趣的可以查看相关的信息!

5.javap -s Main

 

\
 输出内部类型签名


6.javap -v Main

 \


输出栈大小,方法参数的个数

 


 

点击复制链接 与好友分享! 回本站首页
分享到: 更多
您对本文章有什么意见或着疑问吗?请到 论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇: constant——解析
























































































































































也许我们很少会使用到javap工具,因为现在有很多好的反编译工具,但是我在此介绍这个工具不是使用它进行反编译,而是查看java编译器为我们生成的字节码,通过比较字节码和源代码,我们可以发现很多的问题,一个很重要的作用就是了解很多编译器内部的工作机制,在笔者以前的几篇文章中就是借助此工具的,本站有这些文章的原文《深入剖析java类的构造方式》和《使用String还是StringBuffer》。
  下面我们通过具体的一个例子来简单的讲讲这个工具的作用,你不需要很深入的使用,这个简单的介绍和简单的使用就可以使你受益非浅。
  源代码:
  class StringTest 
  {
  public static void main(String[] args) 
  {
  String result="";
  result+="ok";
  }
  }
  在反编译前你当然需要先编译这个类了:javac -g StringTest.java(使用-g参数是因为要得到下面javap -l时的输出需要使用此选项)
  编译完成后,我们在使用不同的选项看看不同的效果:
  
  1、先看看最简单的不带参数的情况:javap StringTest:
  
  Compiled from StringTest.java
  class StringTest extends java.lang.Object {
  StringTest();
  public static void main(java.lang.String[]);
  }
  不带参数的情况将答应类的public信息,包括成员和方法
  从上面的输出中我们确定了两个知识:如果类没有显示的从其它类派生那么它就是从Object派生;如果没有为类显示的申明构造方法,那么编译器将为之生成一个缺省构造方法(不带参数的构造方法)
  
  2、javap -c StringTest:
  
  Compiled from StringTest.java
  class StringTest extends java.lang.Object {
  StringTest();
  public static void main(java.lang.String[]);
  }
  Method StringTest()
  0 aload_0
  1 invokespecial #1 <Method java.lang.Object()>
  4 return
  
  Method void main(java.lang.String[])
  0 ldc #2 <String "">
  2 astore_1
  3 new #3 <Class java.lang.StringBuffer>
  6 dup
  7 invokespecial #4 <Method java.lang.StringBuffer()>
  10 aload_1
  11 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)>
  14 ldc #6 <String "ok">
  16 invokevirtual #5 <Method java.lang.StringBuffer append(java.lang.String)>
  19 invokevirtual #7 <Method java.lang.String toString()>
  22 astore_1
  23 return
  带-p参数将额外的打印字节码信息
  前面的和不带参数的输出一样,后面的显示了方法的具体的字节码,从这个输出里面我们又可以了解更多的内容,首先是编译器生成的的缺省构造方法的内容为调用父类的构造方法super()(需要说明的是使用DJ反编译的源代码中这个缺省构造方法没有这个调用,这可能是该反编译器的一种优化),main()方法的字节码信息的内容可以参考《使用String还是StringBuffer》一文的叙述。
  
  3、javap -l StringTest :
  
  Compiled from StringTest.java
  class StringTest extends java.lang.Object {
  StringTest();
  public static void main(java.lang.String[]);
  }
  
  Line numbers for method StringTest()
  line 1: 0
  
  Local variables for method StringTest()
  StringTest this pc=0, length=5, slot=0
  
  Line numbers for method void main(java.lang.String[])
  line 5: 0
  line 6: 3
  line 7: 23
  
  Local variables for method void main(java.lang.String[])
  java.lang.String[] args pc=0, length=24, slot=0
  java.lang.String result pc=3, length=20, slot=1
  -l参数将显示行号和局部变量表
  从上面的输出中我们可以得到方法中的变量和方法的源代码对于字节码信息的,例如对应main()方法,它的变量为输入参数args以及局部变量result,方法的源代码的第5行对应字节码的第0个偏移量,第5行对应字节码的第3个偏移量,而第7行对应字节码的第23偏移量(参看javap -c的输出前面的偏移量),第7行实际是没有语句的,但是有一个隐含的return,而偏移量23实际对应的也是return调用
  
  4、javap -p StringTest:
  
  Compiled from StringTest.java
  class StringTest extends java.lang.Object {
  StringTest();
  public static void main(java.lang.String[]);
  }
  -p参数将额外的打印private成员和方法的信息,因为这个类没有因此输出相同
  
  这几个参数几乎就可以构成javap的最常使用的集合,最常用的应该还是-c选项,因为可以打印字节码的信息,关于这些字节码的详细涵义在Java 虚拟机规范中定义.

javap是JDK自带的反汇编器,可以查看java编译器为我们生成的字节码。通过它,我们可以对照源代码和字节码,从而了解很多编译器内部的工作。
语法:
   javap [ 命令选项 ] class. . .
  javap 命令用于解析类文件。其输出取决于所用的选项。若没有使用选项,javap 将输出传递给它的类的 public 域及方法。javap 将其输出到标准输出设备上。
命令选项
   -help  输出 javap 的帮助信息。
   -l  输出行及局部变量表。
   -b  确保与 JDK 1.1 javap 的向后兼容性。
   -public  只显示 public 类及成员。
   -protected  只显示 protected 和 public 类及成员。
   -package  只显示包、protected 和 public 类及成员。这是缺省设置。
   -private  显示所有类和成员。
   -J[flag]  直接将 flag 传给运行时系统。
   -s  输出内部类型签名。
   -c  输出类中各方法的未解析的代码,即构成 Java 字节码的指令。
   -verbose  输出堆栈大小、各方法的 locals 及 args 数, 以及class文件的编译版本
   -classpath [路径] 指定 javap 用来查找类的路径。如果设置了该选项,则它将覆盖缺省值或 CLASSPATH 环境变量。目录用冒号分隔。
- bootclasspath [路径] 指定加载自举类所用的路径。缺省情况下,自举类是实现核心 Java 平台的类,位于 jrelib
  t.jar 和 jrelibi18n.jar 中。
   -extdirs[dirs]  覆盖搜索安装方式扩展的位置。扩展的缺省位置是 jrelibext。
实例1:
Hello. java文件
public class Hello
{
static void main(String args[])
{
int i=10;
int j=100;
int m=i*(i+j);
System.out.println("m:"+m);
}
}
然后再执行以下命令:
javac Hello.java
javap -c Hello
得到
Compiled from "Hello.java"
public class Hello extends java.lang.Object{
public Hello();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

static void main(java.lang.String[]);
Code:
0:  bipush  10
2: istore_1
3:  bipush  100
5: istore_2
6: iload_1
7: iload_1
8: iload_2
9: iadd
10: imul
11: istore_3
12: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
15: new #3; //class java/lang/StringBuilder
18: dup
19: invokespecial














  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值