javap学习总结

155 篇文章 2 订阅

javap的基本用法

http://blog.csdn.net/hantiannan/article/details/7659904


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下面。
  -extdirs[dirs] 覆盖搜索安装方式扩展的位置。扩展的缺省位置是 jrelibext。


英文说明:
C:\>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


示例:
下面也经典的StringBuilder代替String做字符串的例子。
[java] view plain copy print?
public class JAVAPTest {  
    public static void main(String[] args) {  
  
    }  
  
    public static String contactWithStringNoLoopNoPara() {  
        String s = "This is " + " my " + "first JAVAP test code.";  
        return s;  
    }  
      
    public static String contactWithStringNoLoop(int count) {  
        String s = "This is " + " my " + count + "th JAVAP test code.";  
        return s;  
    }  
      
    public static String contactWithStringLoop(int count) {  
        String s = "";  
        for (int i = 0; i < count; i++) {  
            s += i;  
        }  
        return s;  
    }  
  
    public static String contactWithStringBufferLoop(int count) {  
        StringBuffer sb = new StringBuffer();  
        for (int i = 0; i < count; i++) {  
            sb.append(i);  
        }  
        return sb.toString();  
    }  
}  


先编译:javac JAVAPTest.java
执行反编译:javap -c JAVAPTest         //注意这个地方不需要class后缀。
结果如下:
[java] view plain copy print?
Compiled from "JAVAPTest.java"  
public class JAVAPTest extends java.lang.Object{  
public JAVAPTest();  
  Code:  
   0:   aload_0  
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V  
   4:   return  
  
public static void main(java.lang.String[]);  
  Code:  
   0:   return  
  
public static java.lang.String contactWithStringNoLoopNoPara();  
  Code:  
   0:   ldc     #2; //String This is  my first JAVAP test code.  
   2:   astore_0  
   3:   aload_0  
   4:   areturn  
  
public static java.lang.String contactWithStringNoLoop(int);  
  Code:  
   0:   new     #3; //class java/lang/StringBuilder  
   3:   dup  
   4:   invokespecial   #4; //Method java/lang/StringBuilder."<init>":()V  
   7:   ldc     #5; //String This is  my  
   9:   invokevirtual   #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;  
   12:  iload_0  
   13:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;  
   16:  ldc     #8; //String th JAVAP test code.  
   18:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;  
   21:  invokevirtual   #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;  
   24:  astore_1  
   25:  aload_1  
   26:  areturn  
  
public static java.lang.String contactWithStringLoop(int);  
  Code:  
   0:   ldc     #10; //String  
   2:   astore_1  
   3:   iconst_0  
   4:   istore_2  
   5:   iload_2  
   6:   iload_0  
   7:   if_icmpge       35  
   10:  new     #3; //class java/lang/StringBuilder  
   13:  dup  
   14:  invokespecial   #4; //Method java/lang/StringBuilder."<init>":()V  
   17:  aload_1  
   18:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;  
   21:  iload_2  
   22:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;  
   25:  invokevirtual   #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;  
   28:  astore_1  
   29:  iinc    2, 1  
   32:  goto    5  
   35:  aload_1  
   36:  areturn  
  
public static java.lang.String contactWithStringBufferLoop(int);  
  Code:  
   0:   new     #11; //class java/lang/StringBuffer  
   3:   dup  
   4:   invokespecial   #12; //Method java/lang/StringBuffer."<init>":()V  
   7:   astore_1  
   8:   iconst_0  
   9:   istore_2  
   10:  iload_2  
   11:  iload_0  
   12:  if_icmpge       27  
   15:  aload_1  
   16:  iload_2  
   17:  invokevirtual   #13; //Method java/lang/StringBuffer.append:(I)Ljava/lang/StringBuffer;  
   20:  pop  
   21:  iinc    2, 1  
   24:  goto    10  
   27:  aload_1  
   28:  invokevirtual   #14; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;  
   31:  areturn  
  
}  


有这个结果我们可以知道。
1。contactWithStringNoLoopNoPara方法中,代码里面是字符串拼接,貌似需要是用StringBuilder替换的好。其实在看了上面的反编译结果后,已经自动组合成一个固定字符串了。因此完全没有必要使用StringBuilder。
[java] view plain copy print?
0:   ldc     #2; //String This is  my first JAVAP test code.  
2。contactWithStringNoLoop方法中,因为使用到了变量,貌似需要是用StringBuilder替换的好。其实在看了上面的反编译结果后,已经自动使用了StringBuilder。所以代码也没有必要使用StringBuilder。


3. contactWithStringLoop方法中,是循环拼接字符串,貌似需要是用StringBuilder替换的好。看了反编译后,每个循环里面都各自生成了一个StringBuilder,并将StringBuilder.toString()防赋值给我们的Sring变量。而我们希望的是只生成一个StringBuilder对象。因此改为StringBuilder的好。循环的时候改为contactWithBufferLoop的方法最好。


4.contactWithBufferLoop方法中,是循环拼接字符串。也是我们预想的步骤在执行。
========

使用javap反编译Java字节码文件

http://www.365mini.com/page/javap-disassemble-class-file-code.htm


在上一篇文章《StringBuilder、StringBuffer与Java字符串处理》中,我们反汇编了Java字节码文件,通过查看编译器编译后的字节命令,我们能够更清楚地了解Java在字符串拼接等方面的处理机制。


那么,我们如何反编译指定的Java字节码文件呢?其实,在Sun公司提供的JDK中,就已经内置了Java字节码文件反编译工具javap.exe(位于JDK安装目录的bin文件夹下)。


我们可以在dos窗口中使用javap来反汇编指定的Java字节码文件。在使用javap的相关dos命令之前,你必须确保已经将JDK安装目录\bin添加到环境变量path中。


接着,我们就可以使用javap来反编译指定的Java字节码文件了。在此之前,我们先通过javap的帮助命令javap -help查看javap相关指令的用法。


javap-help


从上述内容我们可以知道,javap的使用命令格式为javap 选项参数 类名,其中选项参数可以有多个,中间用空格隔开,也可以一个都没有。下面我们编写如下源代码文件(包名test,类名Person),并将其编译为Person.class字节码文件。


package test;public class Person {
    public Person(String name, int age, boolean gender, String address) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.address = address;
    }


    private String name; // private修饰符
    int age; // 默认无访问修饰符(即下面所说的package、friendly)
    protected boolean gender; // protected修饰符
    public String address; // public修饰符


    public String getName() {
        return name;
    }


    public void setName(String name) {
        this.name = name;
    }


    public void sayHi() {
        System.out.println("Hello, my name is " + this.name);
    }
}
接着将包名文件夹test及Person.class放置在D:\java目录下。以便于我们使用javap命令进行测试。


java-person-class


在执行命令之前,我们需要将dos窗口的当前工作目录变更为D:\java\test。


cd-current-dir


1、使用不带任何选项参数的命令:javap Person


javap-person


javap Person和javap -package Person的显示结果一样,因为-package选项参数是默认的,用于显示package(不带任何访问修饰符,即我们常说的friendly)、protected、public修饰的类或成员。


备注:在dos下进入工作目录D:\java,然后使用命令javap test.Person也可以实现上述操作。下同。
2、使用命令:javap -public Person显示public修饰的类或成员。


javap-public-person


与此类似,选项参数-protected用于显示protected以上访问级别(protected、public)的类或成员;选项参数-private用于显示private以上访问级别,也就是所有的类或成员。


3、使用命令:javap -public -l Person显示public修饰的类或成员,并显示行号表格和本地变量表格。


javap-public-l-person


4、使用命令:javap -c Person显示Person.class反汇编出的字节码命令。


javap-c-person


由于选项参数之间组合较多,因此其他选项参数不再一一截图赘述,仅在下面使用文字进行说明:


-classpath <pathlist>
手动指定用户class字节码文件的存放目录,javap程序将在此目录下查找class文件,多个路径以英文分号分隔。例如:javap -classpath D:\java\test Person(即使DOS窗口的当前工作目录为其他任意路径,该命令均可正确执行)。
-s
打印变量的内部类型签名,例如:javap -classpath D:\java\test -s Person。
-extdirs <dirs>
指定javap搜索已安装的java扩展的位置,默认的java扩展的位置为jre\lib\ext。例如:javap -classpath D:\java\test -extdirs D:\java\myext Person
-bootclasspath <pathlist>
指定使用Java底层类加载器(bootstrap class loader)加载的字节码文件的位置。例如:javap -classpath D:\java\test -bootclasspath D:\java\core Person
-verbose
打印方法参数和本地变量的数量以及栈区大小。
-J<flag>
使用javap.exe来执行java.exe虚拟机的相关命令,例如javap -J-version相当于java -version,可以有多个命令,中间以空格隔开。
========

在eclipse中使用javap

http://blog.sina.com.cn/s/blog_6e5e78bf0101okuj.html
javap是sun提供的对class文件进行反编译的工具
1、配置Run---external tools---external tools configurations
选择Program 新建javap运行方式
设置location、workspace等选项
如下图:


需要注意的是workspace选择和argument配置
workding directory 设置为${workspace_loc}/${project_name} ,
Arguments:  
         -c -verbose -classpath ${workspace_loc}/${project_name}/bin ${java_type_name}
如果设置错误会提示cannot find xxx类的错误,或者是有关java_type_name empty的错误
arguments要加上java_type_name,否则会提示No classes were specified on the command line
2、Run


Compiled from "HelloWorld.java"
public class testJava.src.HelloWorld extends java.lang.Object
  SourceFile: "HelloWorld.java"
  minor version: 0
  major version: 50
  Constant pool:
const #1 = class #2; //  testJava/src/HelloWorld
const #2 = Asciz testJava/src/HelloWorld;
const #3 = class #4; //  java/lang/Object
const #4 = Asciz java/lang/Object;
const #5 = Asciz ;
const #6 = Asciz ()V;
const #7 = Asciz Code;
const #8 = Method #3.#9; //  java/lang/Object."":()V
const #9 = NameAndType #5:#6;//  "":()V
const #10 = Asciz LineNumberTable;
const #11 = Asciz LocalVariableTable;
const #12 = Asciz this;
const #13 = Asciz LtestJava/src/HelloWorld;;
const #14 = Asciz main;
const #15 = Asciz ([Ljava/lang/String;)V;
const #16 = Field #17.#19; //  java/lang/System.out:Ljava/io/PrintStream;
const #17 = class #18; //  java/lang/System
const #18 = Asciz java/lang/System;
const #19 = NameAndType #20:#21;//  out:Ljava/io/PrintStream;
const #20 = Asciz out;
const #21 = Asciz Ljava/io/PrintStream;;
const #22 = String #23; //  Hello, world!
const #23 = Asciz Hello, world!;
const #24 = Method #25.#27; //  java/io/PrintStream.println:(Ljava/lang/String;)V
const #25 = class #26; //  java/io/PrintStream
const #26 = Asciz java/io/PrintStream;
const #27 = NameAndType #28:#29;//  println:(Ljava/lang/String;)V
const #28 = Asciz println;
const #29 = Asciz (Ljava/lang/String;)V;
const #30 = Asciz args;
const #31 = Asciz [Ljava/lang/String;;
const #32 = Asciz SourceFile;
const #33 = Asciz HelloWorld.java;


{
public testJava.src.HelloWorld();
  Code:
   Stack=1, Locals=1, Args_size=1
   0: aload_0
   1: invokespecial #8; //Method java/lang/Object."":()V
   4: return
  LineNumberTable: 
   line 3: 0


  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      5      0    this       LtestJava/src/HelloWorld;




public static void main(java.lang.String[]);
  Code:
   Stack=2, Locals=1, Args_size=1
   0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
   3: ldc #22; //String Hello, world!
   5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8: return
  LineNumberTable: 
   line 10: 0
   line 12: 8


  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      9      0    args       [Ljava/lang/String;




}


另外点击javap运行按钮时 先选中需要被运行的.java文件
========

javap(反汇编命令)详解

http://blog.csdn.net/hudashi/article/details/7062668 
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+j;
System.out.println("m:"+m);
}
int get()
{
int a=1;
int b=2;
int c=3;
int d=4;
int e=5;
int f=6;
int n=a+b+c+d+e+f;
return n;
}
static int get2()
{
int a=1;
int b=12;
int c=39;
int d=a+b;
return d;
}
}
然后再执行以下命令:
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_2
   8:
iadd
   9:
istore_3
   10:
getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   13:
new #3; //class java/lang/StringBuilder
   16:
dup
   17:
invokespecial #4; //Method java/lang/StringBuilder."<init>":()V
   20:
ldc #5; //String m:
   22:
invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   25:
iload_3
   26:
invokevirtual #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   29:
invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   32:
invokevirtual #9; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   35:
return


int get();
  Code:
   0:
iconst_1
   1:
istore_1
   2:
iconst_2
   3:
istore_2
   4:
iconst_3
   5:
istore_3
   6:
iconst_4
   7:
istore 4
   9:
iconst_5
   10:
istore 5
   12:
bipush 6
   14:
istore
6
   16:
iload_1
   17:
iload_2
   18:
iadd
   19:
iload_3
   20:
iadd
   21:
iload 4
   23:
iadd
   24:
iload 5
   26:
iadd
   27:
iload 6
   29:
iadd
   30:
istore 7
   32:
iload 7
   34:
ireturn


static int get2();
  Code:
   0:
iconst_1
   1:
istore_0
   2:
bipush 12
   4:
istore_1
   5:
bipush 39
   7:
istore_2
   8:
iload_0
   9:
iload_1
   10:
iadd
   11:
istore_3
   12:
iload_3
   13:
ireturn


}
另外关于如何使用javap命令查看class文件的编译版本请参考《用javap查看编译版本》
========
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值