您的位置:首页 > 编程语言 > Java开发

javap学习总结

2016-08-28 20:46 239 查看

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查看编译版本》

========
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java class jdk javap