17.4 class文件结构 - 使用javap指令解析Class文件
使用javap指令解析Class文件
解析字节码的作用
通过反编译生成的字节码文件,我们可以深入的了解java代码的工作机制。但是,自己分析类文件结构太麻烦了!除了使用第三方的jclasslib工具之外,oracle官方也提供了工具:javap。
javap是jdk自带的反解析工具。它的作用就是根据class字节码文件,反解析出当前类对应的code区(字节码指令)、局部变量表、异常表和代码行偏移量映射表、常量池等信息。
通过局部变量表,我们可以查看局部变量的作用域范围、所在槽位等信息,甚至可以看到槽位复用等信息。
javac -g操作
解析字节码文件得到的信息中,有些信息(如局部变量表、指令和代码行偏移量映射表、常量池中方法的参数名称等等)需要在使用javac编译成class文件时,指定参数才能输出。
比如,你直接javac xx.java, 就不会在生成对应的局部变量表等信息,如果你使用javac -g xx. java就可以生成所有相关信息了。如果你使用的eclipse或IDEA,则默认情况下,eclipse、 IDEA在编译时会帮你生成局部变量表、指令和代码行偏移量映射表等信息的。
javap的用法
javap的用法格式:
javap
其中,classes就是你要反编译的class文件。
在命令行中直接输入javap或javap -help可 以看到javap的options有如下选项:
这里重组一下:
-help --help -? 输出此用法消息-version 版本信息-public 仅显示公共类和成员-protected 显示受保护的/公共类和成员-p -private 显示所有类和成员-package 显示程序包/受保护的/公共类和成员(默认)-sysinfo 显示正在处理的类的系统信息(路径,大小,日期,MD5 散列)-constants 显示最终常量-s 输出内部类型签名-l 输出行号和本地变量表-c 对代码进行反汇编-v -verbose 输出附加信息-classpath <path> 指定查找用户类文件的位置-bootclasspath <path> 覆盖引导类文件的位置
一般常用的是-v -l -c三个选项。
javap -l 会输出行号和本地变量表信息。
javap -c 会对当前class字节码进行反编译生成汇编代码。
javap -v classxx 除了包含-c内容外,还会输出行号、局部变量表信息、常量池等信息。
注意:
- -v相当于-c -l
- -v也不会输出私有的字段、方法等信息,所以如果想输出私有的信息,那需要在-v后面加上-p才行
使用举例
代码
public class JavapTest {
private int num;
boolean flag;
protected char gender;
public String info;public static final int *COUNTS* = 1;
static {String url = "www.baidu.com";}{
info = "java";}
public JavapTest() {}
private JavapTest(boolean falg) {
this.flag = flag;}
private void methodPrivate() {}
int getNum(int i) {
return num + i;}
protected char showGender() {
return gender;}
public void showInfo() {
int i = 100;System.out.println(info + i);}
}
字节码文件分析
Classfile /C:/......./JavapTest.class // 字节码文件所属的路径Last modified 2021-2-24; size 1393 bytes // 最后修改时间,字节码文件的大小MD5 checksum 2c764244fa3a95bfb346c9e416a7a3f6 // MD5散列值Compiled from "JavapTest.java" // 源文件的名称
public class io.test.JavapTestminor version: 0 // 副版本major version: 52 // 主版本flags: ACC_PUBLIC, ACC_SUPER // 访问标识
*************************** 常量池********************************
Constant pool:#1 = Methodref #16.#48 // java/lang/Object."":()V#2 = String #49 // java#3 = Fieldref #15.#50 // io/test/JavapTest.info:Ljava/lang/String;#4 = Fieldref #15.#51 // io/test/JavapTest.flag:Z#5 = Fieldref #15.#52 // io/test/JavapTest.num:I#6 = Fieldref #15.#53 // io/test/JavapTest.gender:C#7 = Fieldref #54.#55 // java/lang/System.out:Ljava/io/PrintStream;#8 = Class #56 // java/lang/StringBuilder#9 = Methodref #8.#48 // java/lang/StringBuilder."":()V#10 = Methodref #8.#57 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;#11 = Methodref #8.#58 // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;#12 = Methodref #8.#59 // java/lang/StringBuilder.toString:()Ljava/lang/String;#13 = Methodref #60.#61 // java/io/PrintStream.println:(Ljava/lang/String;)V#14 = String #62 // www.baidu.com#15 = Class #63 // io/test/JavapTest#16 = Class #64 // 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 #29 = Utf8 ()V#30 = Utf8 Code#31 = Utf8 LineNumberTable#32 = Utf8 LocalVariableTable#33 = Utf8 this#34 = Utf8 Lio/test/JavapTest;#35 = Utf8 (Z)V#36 = Utf8 falg#37 = Utf8 MethodParameters#38 = Utf8 methodPrivate#39 = Utf8 getNum#40 = Utf8 (I)I#41 = Utf8 i#42 = Utf8 showGender#43 = Utf8 ()C#44 = Utf8 showInfo#45 = Utf8 #46 = Utf8 SourceFile#47 = Utf8 JavapTest.java#48 = NameAndType #28:#29 // "":()V#49 = Utf8 java#50 = NameAndType #23:#24 // info:Ljava/lang/String;#51 = NameAndType #19:#20 // flag:Z#52 = NameAndType #17:#18 // num:I#53 = NameAndType #21:#22 // gender:C#54 = Class #65 // java/lang/System#55 = NameAndType #66:#67 // out:Ljava/io/PrintStream;#56 = Utf8 java/lang/StringBuilder#57 = NameAndType #68:#69 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;#58 = NameAndType #68:#70 // append:(I)Ljava/lang/StringBuilder;#59 = NameAndType #71:#72 // toString:()Ljava/lang/String;#60 = Class #73 // java/io/PrintStream#61 = NameAndType #74:#75 // println:(Ljava/lang/String;)V#62 = Utf8 www.baidu.com#63 = Utf8 io/test/JavapTest#64 = Utf8 java/lang/Object#65 = Utf8 java/lang/System#66 = Utf8 out#67 = Utf8 Ljava/io/PrintStream;#68 = Utf8 append#69 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;#70 = Utf8 (I)Ljava/lang/StringBuilder;#71 = Utf8 toString#72 = Utf8 ()Ljava/lang/String;#73 = Utf8 java/io/PrintStream#74 = Utf8 println#75 = Utf8 (Ljava/lang/String;)V
******************************字段表集合的信息**************************************
{private int num; // 字段名descriptor: I // 字段表集合的信息flags: ACC_PRIVATE // 字段的访问标识boolean 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 1 // 常量字段的属性:ConstantValue
******************************方法表集合的信息**************************************public io.test.JavapTest(); // 无参构造器方法信息descriptor: ()Vflags: ACC_PUBLICCode:stack=2, locals=1, args_size=10: aload_01: invokespecial #1 // Method java/lang/Object."":()V4: aload_05: ldc #2 // String java7: putfield #3 // Field info:Ljava/lang/String;10: returnLineNumberTable:line 16: 0line 14: 4line 18: 10LocalVariableTable:Start Length Slot Name Signature0 11 0 this Lio/test/JavapTest;private io.test.JavapTest(boolean); // 单个参数构造器方法信息descriptor: (Z)Vflags: ACC_PRIVATECode:stack=2, locals=2, args_size=20: aload_01: invokespecial #1 // Method java/lang/Object."":()V4: aload_05: ldc #2 // String java7: putfield #3 // Field info:Ljava/lang/String;10: aload_011: aload_012: getfield #4 // Field flag:Z15: putfield #4 // Field flag:Z18: returnLineNumberTable:line 19: 0line 14: 4line 20: 10line 21: 18LocalVariableTable:Start Length Slot Name Signature0 19 0 this Lio/test/JavapTest;0 19 1 falg ZMethodParameters:Name Flagsfalgprivate void methodPrivate();descriptor: ()Vflags: ACC_PRIVATECode:stack=0, locals=1, args_size=10: returnLineNumberTable:line 24: 0LocalVariableTable:Start Length Slot Name Signature0 1 0 this Lio/test/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 26: 0LocalVariableTable:Start Length Slot Name Signature0 7 0 this Lio/test/JavapTest;0 7 1 i IMethodParameters:Name Flagsiprotected char showGender();descriptor: ()Cflags: ACC_PROTECTEDCode:stack=1, locals=1, args_size=10: aload_01: getfield #6 // Field gender:C4: ireturnLineNumberTable:line 29: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 this Lio/test/JavapTest;public void showInfo();descriptor: ()V // 方法的描述符:方法的形参列表、返回值类型flags: ACC_PUBLIC // 方法的访问标识Code: // 方法的Code属性stack=3, locals=2, args_size=1 // stack:操作数栈的最大深度 locals:局部变量表的长度 args_size:方法接受参数的个数
// 偏移量 操作码 操作数0: bipush 1002: 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."":()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: return
// 行号表:指明字节码指令的偏移量与java源代码中代码的行号的一一对应关系LineNumberTable:line 32: 0line 33: 3line 34: 30// 局部变量表:描述内部局部变量的相关信息LocalVariableTable:Start Length Slot Name Signature0 31 0 this Lio/test/JavapTest;3 28 1 i Istatic {};descriptor: ()Vflags: ACC_STATICCode:stack=1, locals=1, args_size=00: ldc #14 // String www.baidu.com2: astore_03: returnLineNumberTable:line 11: 0line 12: 3LocalVariableTable:Start Length Slot Name Signature
}
SourceFile: "JavapTest.java" // 附加属性:指明当前字节码文件对应的源程序文件名
jclasslib展示的内容
总结
通过javap命令可以查看一个java类反汇编得到的Class文件版本号、常量池、访问标识、变量表、指令代码行号表等等信息。不显示类索引、父类索引、接口索引集合、()、 ()等结构
通过对前面例子代码反汇编文件的简单分析,可以发现,一个方法的执行通常会涉及下面几块内存的操作:
- java栈中:局部变量表、操作数栈。
- java堆。通过对象的地址引用去操作。
- 常量池。
- 其他如帧数据区、方法区的剩余部分等情况,测试中没有显示出来,这里说明一下。
平常,我们比较关注的是java类中每个方法的反汇编中的指令操作过程,这些指令都是顺序执行的,可以参考官方文档查看每个指令的含义,很简单:
总结
通过javap命令可以查看一个java类反汇编得到的Class文件版本号、常量池、访问标识、变量表、指令代码行号表等等信息。不显示类索引、父类索引、接口索引集合、()、 ()等结构
通过对前面例子代码反汇编文件的简单分析,可以发现,一个方法的执行通常会涉及下面几块内存的操作:
- java栈中:局部变量表、操作数栈。
- java堆。通过对象的地址引用去操作。
- 常量池。
- 其他如帧数据区、方法区的剩余部分等情况,测试中没有显示出来,这里说明一下。
平常,我们比较关注的是java类中每个方法的反汇编中的指令操作过程,这些指令都是顺序执行的,可以参考官方文档查看每个指令的含义,很简单:
https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html
17.4 class文件结构 - 使用javap指令解析Class文件相关推荐
- 使用javap指令解析Class文件
接卸字节码的作用 通过反编译生成的字节码文件,我们可以深入的了解Java代码的工作机制.但是,自己分析类文件结构太麻烦了!除了使用第三方的jclasslib工具之外,oracle官方也提供了工具:ja ...
- jvm中篇-04-Javap指令解析class文件
jvm中篇-04-Javap指令解析class文件 解析字节码的作用 javac -g 操作 javap 的具体用法 使用举例 小结 234-237 解析字节码的作用 通过反编译生成的字节码文件,我们 ...
- Java的 Class字节码文件结构和内容全面解析【两万字】
了解Class文件的结构组成,对于我们后续的JVM以及Java原理深入学习是很有帮助的,因为Class文件帮我们默默的做了很多事,比如.为什么对象方法中可以直接使用this变量?!本文将带领大家,一步 ...
- 使用批处理查看.class文件内容--javap指令
想研究java的class的小伙伴注意了. 查看.class文件内容--javap指令 用到的指令是 javap -verbose 目标.class 文末给出了批处理脚本 首先我们看: 一个简易的输出 ...
- XCP实战系列介绍16-XCP标定过程指令解析
本文框架 1.前言 2. XCP标定过程指令解析 1.前言 前面几篇文章我们介绍了XCP底层原理,配置方法及基于CANape,CANoe或Vehicle SPY进行观测或标定的方法,在本篇中我们将对标 ...
- 解读乐鑫 AT 指令解析器,解锁你不知道的用法
文章首发于 『物联网学前班』公众号,欢迎关注.星标获取即时信息. 由于近期正好在做这个事情,所以今天就以乐鑫的 AT 指令为例,讲讲 AT 解析器设计有哪些事情,也算是个自己近期的学习总结了. 往期文 ...
- CPU指令解析及函数调用机制
目录 一.CPU指令解析 最常用的mov指令 对栈进行push和pop 二.函数的调用机制 一.CPU指令解析 最常用的mov指令 指令中最常使用的是对寄存器和内存进行数据存储的 mov 指定数据的存 ...
- Windows BAT脚本常用指令解析
BAT脚本入门 一.概述 首先解决第一个问题,什么是BAT脚本? BAT脚本也叫批处理文本,批处理文件是无格式的文本文件,它包含一条或多条命令.它的文件扩展名为 .bat 或 .cmd.在命令提示下键 ...
- 记: 对于SCPI指令以及相同类型指令解析器的指令压缩方式
0x10 前言 SCPI是一个对人或者说用户十分友好的语言,采用了人性化的抽象与对于用户很友善的组成方式. 但是对于某些机器的设计就会很难受,而且当前的机器会在日后的不停更新导致当前的程序越来越呈现一 ...
最新文章
- SAP ECM的相关设定(ECN)
- ActiveMQ与xml rpc
- Django中扩展Paginator实现分页
- 电脑故障速排方法-显卡篇
- matlab 值法确定各指标权重,Matlab学习系列19. 熵值法确定权重
- INTEL和AMD两大巨头的前身
- protobuf windows lib链接库生成
- 2018四川高考文科21题
- Redhat/CentOS修改主机名
- seaborn箱线图_Seaborn线图的数据可视化
- 转载 - Linux使用技巧锦集
- Elasticsearch:Hadoop 大数据集成 (Hadoop => Elasticsearch)
- java定义一个盒子类box_C++定义一个Box(盒子)类 看完你就知道了
- java里面怎么生成备注时间_Android studio 创建java文件时 注解显示作者、日期、时间...
- 关于fi dd ler 手机抓包 网卡地址地址_超详细的网络抓包神器 tcpdump 使用指南
- win10 chrome被毒霸2345劫持主页处理过程与结果
- dropout keep_prob参数
- 百度大脑人体分析服务3月上新盘点
- ESP8266远程控制台灯(硬件软件详解)
- ArcGIS制图——单图层道路压盖处理