1、解析字节码的作用
通过反编译生成的字节码文件,我们可以深入的了解java代码的工作机制。但是,自己分析类文件结构太麻烦了!除了使用第三方的jclasslib工具之外,oracle官方也提供了工具:javap
javap是jdk自带的反解析工具。它的作用就是根据class字节码文件,反解析出当前类对应的code区(字节码指令)、局部变量表、异常表和代码行偏移量映射表、常量池等信息。
通过局部变量表,我们可以查看局部变量的作用域范围、所在槽位等信息,甚至可以看到槽位复用等信息。
2、javac -g操作
解析字节码文件得到的信息中,有些信息(如局部变量表、指令和代码行偏移量映射表、常量池中方法的参数名称等等)需要在使用javac编译成class文件时,指定参数才能输出
比如,你直接javac xx.java,就不会在生成对应的局部变量表等信息,如果你使用javac -g xx.java就可以生成所有相关信息了。如果你使用的eclipse或IDEA,则默认情况下,eclipse、IDEA在编译时会帮你生成局部变量表、指令和代码行偏移量映射表等信息的。
3、javap的用法
javap的用法格式:
javap <options> <classes>
其中,classes就是你要反编译的class文件
在命令行中直接输入javap或javap -help可以看到javap的options有如下选项:
这里重组一下:
-help --help -? 输出此用法消息-version 版本信息,其实是当前javap所在jdk的版本信息,不是class在哪个jdk下生成的。-public 仅显示公共类和成员-protected 显示受保护的/公共类和成员-p -private 显示所有类和成员-package 显示程序包/受保护的/公共类 和成员 (默认)-sysinfo 显示正在处理的类的系统信息 (路径, 大小, 日期, MD5 散列,源文件名)-constants 显示静态最终常量-s 输出内部类型签名-l 输出行号和本地变量表-c 对代码进行反汇编-v -verbose 输出附加信息(包括行号、本地变量表,反汇编等详细信息)-classpath <path> 指定查找用户类文件的位置-cp <path> 指定查找用户类文件的位置-bootclasspath <path> 覆盖引导类文件的位置
一般常用的是-v -l -c三个选项。
javap -l 会输出行号和本地变量表信息。
javap -c 会对当前class字节码进行反编译生成汇编代码。
javap -v classxx 除了包含-c内容外,还会输出行号、局部变量表信息、常量池等信息。
4、使用举例
public class JavapTest {private int num;boolean flag;protected char gender;public String info;public static final int COUNTS = 1;static{String url = "www.atguigu.com";}{info = "java";}public JavapTest(){}private JavapTest(boolean flag){this.flag = flag;}private void methodPrivate(){}int getNum(int i){return num + i;}protected char showGender(){return gender;}public void showInfo(){int i = 10;System.out.println(info + i);}
}
希望输出的信息比较完整的话,使用如下操作:javap -v -p JavapTest.class
对应的内容信息为:
Classfile /C:/Users/songhk/Desktop/2/JavapTest.classLast modified 2020-9-6; size 1358 bytesMD5 checksum 526b4a845e4d98180438e4c5781b7e88Compiled from "JavapTest.java"
public class com.atguigu.java1.JavapTestminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 = Methodref #16.#46 // java/lang/Object."<init>":()V#2 = String #47 // java#3 = Fieldref #15.#48 // com/atguigu/java1/JavapTest.info:Ljava/lang/String;#4 = Fieldref #15.#49 // com/atguigu/java1/JavapTest.flag:Z#5 = Fieldref #15.#50 // com/atguigu/java1/JavapTest.num:I#6 = Fieldref #15.#51 // com/atguigu/java1/JavapTest.gender:C#7 = Fieldref #52.#53 // java/lang/System.out:Ljava/io/PrintStream;#8 = Class #54 // java/lang/StringBuilder#9 = Methodref #8.#46 // java/lang/StringBuilder."<init>":()V#10 = Methodref #8.#55 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;#11 = Methodref #8.#56 // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;#12 = Methodref #8.#57 // java/lang/StringBuilder.toString:()Ljava/lang/String;#13 = Methodref #58.#59 // java/io/PrintStream.println:(Ljava/lang/String;)V#14 = String #60 // www.atguigu.com#15 = Class #61 // com/atguigu/java1/JavapTest#16 = Class #62 // java/lang/Object#17 = Utf8 num#18 = Utf8 I#19 = Utf8 flag#20 = Utf8 Z#21 = Utf8 gender#22 = Utf8 C#23 = Utf8 info#24 = Utf8 Ljava/lang/String;#25 = Utf8 COUNTS#26 = Utf8 ConstantValue#27 = Integer 1#28 = Utf8 <init>#29 = Utf8 ()V#30 = Utf8 Code#31 = Utf8 LineNumberTable#32 = Utf8 LocalVariableTable#33 = Utf8 this#34 = Utf8 Lcom/atguigu/java1/JavapTest;#35 = Utf8 (Z)V#36 = Utf8 methodPrivate#37 = Utf8 getNum#38 = Utf8 (I)I#39 = Utf8 i#40 = Utf8 showGender#41 = Utf8 ()C#42 = Utf8 showInfo#43 = Utf8 <clinit>#44 = Utf8 SourceFile#45 = Utf8 JavapTest.java#46 = NameAndType #28:#29 // "<init>":()V#47 = Utf8 java#48 = NameAndType #23:#24 // info:Ljava/lang/String;#49 = NameAndType #19:#20 // flag:Z#50 = NameAndType #17:#18 // num:I#51 = NameAndType #21:#22 // gender:C#52 = Class #63 // java/lang/System#53 = NameAndType #64:#65 // out:Ljava/io/PrintStream;#54 = Utf8 java/lang/StringBuilder#55 = NameAndType #66:#67 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;#56 = NameAndType #66:#68 // append:(I)Ljava/lang/StringBuilder;#57 = NameAndType #69:#70 // toString:()Ljava/lang/String;#58 = Class #71 // java/io/PrintStream#59 = NameAndType #72:#73 // println:(Ljava/lang/String;)V#60 = Utf8 www.atguigu.com#61 = Utf8 com/atguigu/java1/JavapTest#62 = Utf8 java/lang/Object#63 = Utf8 java/lang/System#64 = Utf8 out#65 = Utf8 Ljava/io/PrintStream;#66 = Utf8 append#67 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;#68 = Utf8 (I)Ljava/lang/StringBuilder;#69 = Utf8 toString#70 = Utf8 ()Ljava/lang/String;#71 = Utf8 java/io/PrintStream#72 = Utf8 println#73 = Utf8 (Ljava/lang/String;)V
{private int num;descriptor: Iflags: ACC_PRIVATEboolean flag;descriptor: Zflags:protected char gender;descriptor: Cflags: ACC_PROTECTEDpublic java.lang.String info;descriptor: Ljava/lang/String;flags: ACC_PUBLICpublic static final int COUNTS;descriptor: Iflags: ACC_PUBLIC, ACC_STATIC, ACC_FINALConstantValue: int 1public com.atguigu.java1.JavapTest();descriptor: ()Vflags: ACC_PUBLICCode:stack=2, locals=1, args_size=10: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: aload_05: ldc #2 // String java7: putfield #3 // Field info:Ljava/lang/String;10: returnLineNumberTable:line 20: 0line 18: 4line 22: 10LocalVariableTable:Start Length Slot Name Signature0 11 0 this Lcom/atguigu/java1/JavapTest;private com.atguigu.java1.JavapTest(boolean);descriptor: (Z)Vflags: ACC_PRIVATECode:stack=2, locals=2, args_size=20: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: aload_05: ldc #2 // String java7: putfield #3 // Field info:Ljava/lang/String;10: aload_011: iload_112: putfield #4 // Field flag:Z15: returnLineNumberTable:line 23: 0line 18: 4line 24: 10line 25: 15LocalVariableTable:Start Length Slot Name Signature0 16 0 this Lcom/atguigu/java1/JavapTest;0 16 1 flag Zprivate void methodPrivate();descriptor: ()Vflags: ACC_PRIVATECode:stack=0, locals=1, args_size=10: returnLineNumberTable:line 28: 0LocalVariableTable:Start Length Slot Name Signature0 1 0 this Lcom/atguigu/java1/JavapTest;int getNum(int);descriptor: (I)Iflags:Code:stack=2, locals=2, args_size=20: aload_01: getfield #5 // Field num:I4: iload_15: iadd6: ireturnLineNumberTable:line 30: 0LocalVariableTable:Start Length Slot Name Signature0 7 0 this Lcom/atguigu/java1/JavapTest;0 7 1 i Iprotected char showGender();descriptor: ()Cflags: ACC_PROTECTEDCode:stack=1, locals=1, args_size=10: aload_01: getfield #6 // Field gender:C4: ireturnLineNumberTable:line 33: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 this Lcom/atguigu/java1/JavapTest;public void showInfo();descriptor: ()Vflags: ACC_PUBLICCode:stack=3, locals=2, args_size=10: bipush 102: istore_13: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;6: new #8 // class java/lang/StringBuilder9: dup10: invokespecial #9 // Method java/lang/StringBuilder."<init>":()V13: aload_014: getfield #3 // Field info:Ljava/lang/String;17: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;20: iload_121: invokevirtual #11 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;24: invokevirtual #12 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;27: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;)V30: returnLineNumberTable:line 36: 0line 37: 3line 38: 30LocalVariableTable:Start Length Slot Name Signature0 31 0 this Lcom/atguigu/java1/JavapTest;3 28 1 i Istatic {};descriptor: ()Vflags: ACC_STATICCode:stack=1, locals=1, args_size=00: ldc #14 // String www.atguigu.com2: astore_03: returnLineNumberTable:line 15: 0line 16: 3LocalVariableTable:Start Length Slot Name Signature
}
SourceFile: "JavapTest.java"