Java 虚拟机之六:javap工具
一:简介javap是JDK自带的反汇编器,可以查看java编译器为我们生成的字节码。通过它,我们可以对照源代码和字节码,从而了解很多编译器内部的工作。javap命令的常用参数有:-l...
一:简介
javap是JDK自带的反汇编器,可以查看java编译器为我们生成的字节码。通过它,我们可以对照源代码和字节码,从而了解很多编译器内部的工作。
javap命令的常用参数有:
-l 打印行和本地变量表
-public 只显示公共类和成员变量
-protected 只显示公共的、受保护的类和变量
-private 显示所有的类和成员变量
-p 显示所有的类和成员变量
-Joption 给jvm指定参数,例如:
javap -J-version
javap -J-Djava.security.manager -J-Djava.security.policy=MyPolicy
-s 打印内部类型签名(用于泛型)
-sysinfo 打印被处理类的系统信息(路径,大小,日志,MD5哈希)
-constants 显示static final常量
-c 输出分解后的代码。例如,类中每一个方法内,包含java字节码的指令
-verbose 输出栈大小,变量(locals)和方法参数的个数
-classpath path 指定查询类的路径.如果设置该值,则会覆盖默认值和CLASSPATH环境变量。
-bootclasspath path 指定启动类的路径,默认值是jre/lib/rt.jar 和 其他少数的jar.
-extdir dirs 覆盖 java.ext.dirs路径
二:实例
1.Java源代码
public class Demo {
private String name = "张三";
public static void main(String args[]) {
System.out.println("Hello World.");
}
private void sayHello() {
System.out.println("Hello " + name);
}
}
2.javac编译后的字节码
CA FE BA BE 00 00 00 34 00 36 0A 00 0D 00 1E 08
00 1F 09 00 0C 00 20 09 00 21 00 22 08 00 23 0A
00 24 00 25 07 00 26 0A 00 07 00 1E 08 00 27 0A
00 07 00 28 0A 00 07 00 29 07 00 2A 07 00 2B 01
00 04 6E 61 6D 65 01 00 12 4C 6A 61 76 61 2F 6C
61 6E 67 2F 53 74 72 69 6E 67 3B 01 00 06 3C 69
6E 69 74 3E 01 00 03 28 29 56 01 00 04 43 6F 64
65 01 00 0F 4C 69 6E 65 4E 75 6D 62 65 72 54 61
62 6C 65 01 00 12 4C 6F 63 61 6C 56 61 72 69 61
62 6C 65 54 61 62 6C 65 01 00 04 74 68 69 73 01
00 28 4C 63 6F 6D 2F 62 72 69 6C 6C 69 61 6E 74
73 74 61 72 2F 63 69 6D 63 2F 69 6D 2F 64 65 73
6B 74 6F 70 2F 44 65 6D 6F 3B 01 00 04 6D 61 69
6E 01 00 16 28 5B 4C 6A 61 76 61 2F 6C 61 6E 67
2F 53 74 72 69 6E 67 3B 29 56 01 00 04 61 72 67
73 01 00 13 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F
53 74 72 69 6E 67 3B 01 00 08 73 61 79 48 65 6C
6C 6F 01 00 0A 53 6F 75 72 63 65 46 69 6C 65 01
00 09 44 65 6D 6F 2E 6A 61 76 61 0C 00 10 00 11
01 00 06 E5 BC A0 E4 B8 89 0C 00 0E 00 0F 07 00
2C 0C 00 2D 00 2E 01 00 0C 48 65 6C 6C 6F 20 57
6F 72 6C 64 2E 07 00 2F 0C 00 30 00 31 01 00 17
6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67
42 75 69 6C 64 65 72 01 00 06 48 65 6C 6C 6F 20
0C 00 32 00 33 0C 00 34 00 35 01 00 26 63 6F 6D
2F 62 72 69 6C 6C 69 61 6E 74 73 74 61 72 2F 63
69 6D 63 2F 69 6D 2F 64 65 73 6B 74 6F 70 2F 44
65 6D 6F 01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F
4F 62 6A 65 63 74 01 00 10 6A 61 76 61 2F 6C 61
6E 67 2F 53 79 73 74 65 6D 01 00 03 6F 75 74 01
00 15 4C 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74
53 74 72 65 61 6D 3B 01 00 13 6A 61 76 61 2F 69
6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 01 00 07
70 72 69 6E 74 6C 6E 01 00 15 28 4C 6A 61 76 61
2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 01
00 06 61 70 70 65 6E 64 01 00 2D 28 4C 6A 61 76
61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 4C
6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67
42 75 69 6C 64 65 72 3B 01 00 08 74 6F 53 74 72
69 6E 67 01 00 14 28 29 4C 6A 61 76 61 2F 6C 61
6E 67 2F 53 74 72 69 6E 67 3B 00 21 00 0C 00 0D
00 00 00 01 00 02 00 0E 00 0F 00 00 00 03 00 01
00 10 00 11 00 01 00 12 00 00 00 39 00 02 00 01
00 00 00 0B 2A B7 00 01 2A 12 02 B5 00 03 B1 00
00 00 02 00 13 00 00 00 0A 00 02 00 00 00 13 00
04 00 14 00 14 00 00 00 0C 00 01 00 00 00 0B 00
15 00 16 00 00 00 09 00 17 00 18 00 01 00 12 00
00 00 37 00 02 00 01 00 00 00 09 B2 00 04 12 05
B6 00 06 B1 00 00 00 02 00 13 00 00 00 0A 00 02
00 00 00 17 00 08 00 18 00 14 00 00 00 0C 00 01
00 00 00 09 00 19 00 1A 00 00 00 02 00 1B 00 11
00 01 00 12 00 00 00 4B 00 03 00 01 00 00 00 1D
B2 00 04 BB 00 07 59 B7 00 08 12 09 B6 00 0A 2A
B4 00 03 B6 00 0A B6 00 0B B6 00 06 B1 00 00 00
02 00 13 00 00 00 0A 00 02 00 00 00 1B 00 1C 00
1C 00 14 00 00 00 0C 00 01 00 00 00 1D 00 15 00
16 00 00 00 01 00 1C 00 00 00 02 00 1D
3.javap返汇编后的内容
javap -p -v Demo
默认情况下javap会打印所有非私有的字段和方法,当加了-p选项后,它还将打印私有的字段和方法;-v 它尽可能地打印所有信息。如果只需要查询方法对应的字节码,那么可以用-c代替-v.
=================基本信息(涵盖了原class文件的相关信息)=======================
Classfile /D:/workspace/donkey/cimc-im-desktop/target/classes/com/brilliantstar/cimc/im/desktop/Demo.class
Last modified 2018-9-6; size 909 bytes
MD5 checksum 0f9cd841c4a2ab1f6a00163e55ca6e0f
Compiled from "Demo.java"
public class com.brilliantstar.cimc.im.desktop.Demo
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
=================常量池(用来存放各种常量及符号引用)=======================
Constant pool:
#1 = Methodref #13.#30 // java/lang/Object."<init>":()V
#2 = String #31 // 张三
#3 = Fieldref #12.#32 // com/brilliantstar/cimc/im/desktop/Demo.name:Ljava/lang/String;
#4 = Fieldref #33.#34 // java/lang/System.out:Ljava/io/PrintStream;
#5 = String #35 // Hello World.
#6 = Methodref #36.#37 // java/io/PrintStream.println:(Ljava/lang/String;)V
#7 = Class #38 // java/lang/StringBuilder
#8 = Methodref #7.#30 // java/lang/StringBuilder."<init>":()V
#9 = String #39 // Hello
#10 = Methodref #7.#40 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#11 = Methodref #7.#41 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#12 = Class #42 // com/brilliantstar/cimc/im/desktop/Demo
#13 = Class #43 // java/lang/Object
#14 = Utf8 name
#15 = Utf8 Ljava/lang/String;
#16 = Utf8 <init>
#17 = Utf8 ()V
#18 = Utf8 Code
#19 = Utf8 LineNumberTable
#20 = Utf8 LocalVariableTable
#21 = Utf8 this
#22 = Utf8 Lcom/brilliantstar/cimc/im/desktop/Demo;
#23 = Utf8 main
#24 = Utf8 ([Ljava/lang/String;)V
#25 = Utf8 args
#26 = Utf8 [Ljava/lang/String;
#27 = Utf8 sayHello
#28 = Utf8 SourceFile
#29 = Utf8 Demo.java
#30 = NameAndType #16:#17 // "<init>":()V
#31 = Utf8 张三
#32 = NameAndType #14:#15 // name:Ljava/lang/String;
#33 = Class #44 // java/lang/System
#34 = NameAndType #45:#46 // out:Ljava/io/PrintStream;
#35 = Utf8 Hello World.
#36 = Class #47 // java/io/PrintStream
#37 = NameAndType #48:#49 // println:(Ljava/lang/String;)V
#38 = Utf8 java/lang/StringBuilder
#39 = Utf8 Hello
#40 = NameAndType #50:#51 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#41 = NameAndType #52:#53 // toString:()Ljava/lang/String;
#42 = Utf8 com/brilliantstar/cimc/im/desktop/Demo
#43 = Utf8 java/lang/Object
#44 = Utf8 java/lang/System
#45 = Utf8 out
#46 = Utf8 Ljava/io/PrintStream;
#47 = Utf8 java/io/PrintStream
#48 = Utf8 println
#49 = Utf8 (Ljava/lang/String;)V
#50 = Utf8 append
#51 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#52 = Utf8 toString
#53 = Utf8 ()Ljava/lang/String;
{
===============字段区域(用来列举该类中的各个字段)===================
private java.lang.String name;
descriptor: Ljava/lang/String;
flags: ACC_PRIVATE
public com.brilliantstar.cimc.im.desktop.Demo();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2 // String 张三
7: putfield #3 // Field name:Ljava/lang/String;
10: return
LineNumberTable:
line 19: 0
line 20: 4
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 this Lcom/brilliantstar/cimc/im/desktop/Demo;
===============方法区域(用来列举该类中的各个方法)=========================
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #5 // String Hello World.
5: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 23: 0
line 24: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 args [Ljava/lang/String;
private void sayHello();
descriptor: ()V
flags: ACC_PRIVATE
Code:
stack=3, locals=1, args_size=1
0: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
3: new #7 // class java/lang/StringBuilder
6: dup
7: invokespecial #8 // Method java/lang/StringBuilder."<init>":()V
10: ldc #9 // String Hello
12: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: aload_0
16: getfield #3 // Field name:Ljava/lang/String;
19: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: invokevirtual #11 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
25: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
28: return
LineNumberTable:
line 27: 0
line 28: 28
LocalVariableTable:
Start Length Slot Name Signature
0 29 0 this Lcom/brilliantstar/cimc/im/desktop/Demo;
}
SourceFile: "Demo.java"
以其中的sayHello()方法为例,除了方法描述以及访问权限之外,方法中还包括最为重要的代码区域。
1).代码区域一开始会声明该方法中的操作数栈(stack=3) 和局部变量数目(locals=1)的最大值,以及该方法接收参数的个数(args_size=1)这里局部变量指的是字节码中的局部变量,而非Java程序中的局部变量。
2).接下来是该方法的字节码,每条字节码均标注了对应的偏移量,这是用来定位字节码的。
3).接下来的行数表(LineNumberTable)则是Java源程序到字节码偏移量的映射。行数表和局部变量均属于调试信息,Java虚拟机并不要求class文件必备这些信息。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/28624388/viewspace-2213687/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/28624388/viewspace-2213687/
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)