官方文档 Javap 命令 (oracle.com)
Javap作用:反汇编类文件
使用方式: javap [options] class
参数讲解
-version 打印版本信息
-public / -protected 显示指定访问权限的字段 / 方法
-c 输出方法的字节码
-s 打印字段或方法的签名
L 代表对象类型:其中图中的 Ljava/lang/Integer 代表Integer这个对象
()代表方法参数签名, V代表void。 所以 ()V代表 方法不接收参数无返回值
I 代表int ,(I)I 代表接收int返回int
-verbose / -v 打印完整的信息(包含编译版本号,常量池,局部变量表,行号等)
PS D:BaiduNetdiskDownloadday07代码TestThreadsrccomcompany> javap -v .Test.class Classfile /D:/BaiduNetdiskDownload/day07/代码/TestThread/src/com/company/Test.class Last modified 2022-1-12; size 504 bytes MD5 checksum 4ac41fffe184b36060a672fdd7031869 Compiled from "Test.java" public class com.company.Test minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #6.#20 // java/lang/Object."":()V #2 = Methodref #21.#22 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer; #3 = Fieldref #5.#23 // com/company/Test.age:Ljava/lang/Integer; #4 = Methodref #21.#24 // java/lang/Integer.intValue:()I #5 = Class #25 // com/company/Test #6 = Class #26 // java/lang/Object #7 = Utf8 age #8 = Utf8 Ljava/lang/Integer; #9 = Utf8 #10 = Utf8 ()V #11 = Utf8 Code #12 = Utf8 LineNumberTable #13 = Utf8 add #14 = Utf8 ()I #15 = Utf8 sub #16 = Utf8 Exceptions #17 = Class #27 // java/lang/Exception #18 = Utf8 SourceFile #19 = Utf8 Test.java #20 = NameAndType #9:#10 // " ":()V #21 = Class #28 // java/lang/Integer #22 = NameAndType #29:#30 // valueOf:(I)Ljava/lang/Integer; #23 = NameAndType #7:#8 // age:Ljava/lang/Integer; #24 = NameAndType #31:#14 // intValue:()I #25 = Utf8 com/company/Test #26 = Utf8 java/lang/Object #27 = Utf8 java/lang/Exception #28 = Utf8 java/lang/Integer #29 = Utf8 valueOf #30 = Utf8 (I)Ljava/lang/Integer; #31 = Utf8 intValue { java.lang.Integer age; descriptor: Ljava/lang/Integer; flags: public com.company.Test(); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object." ":()V 4: aload_0 5: bipush 18 7: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 10: putfield #3 // Field age:Ljava/lang/Integer; 13: return LineNumberTable: line 7: 0 line 9: 4 public int add(); descriptor: ()I flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=1 0: sipush 200 3: istore_1 4: aload_0 5: getfield #3 // Field age:Ljava/lang/Integer; 8: invokevirtual #4 // Method java/lang/Integer.intValue:()I 11: bipush 15 13: iadd 14: ireturn LineNumberTable: line 12: 0 line 13: 4 public static void sub() throws java.lang.Exception; descriptor: ()V flags: ACC_PUBLIC, ACC_STATIC Code: stack=0, locals=0, args_size=0 0: return LineNumberTable: line 17: 0 Exceptions: throws java.lang.Exception } SourceFile: "Test.java"
Constant pool 常量池
定义了当前类的常量
第一列#x为常量池的位置 从1开始
第二列为 该常量类型
第三列为 指向的值
关于常量类型参照以下表格
类型 | 描述 |
---|---|
Utf8 | UTF8编码的字符串 |
Integer | 整形字面量 |
Float | 浮点型字面量 |
Long | 长整型字面量 |
Double | 双精度浮点型字面量 |
Class | 类或接口的符号引用 |
String | 字符串类型字面量 |
Fieldref | 字段的符号引用 |
Methodref | 方法的符号引用 |
InterfaceMethodref | 接口方法的符号引用 |
NamAndType | 字段或方法的部分符号引用 |
MethodHandler | 方法句柄 |
MethodType | 方法类型 |
Dynamic | 表示一个动态计算常量 |
InvokeDynamic | 表示一个动态方法调用点 |
Module | 表示一个模块 |
Package | 表示一个模块中开放或者导出的包 |
LineNumberTable 行号表
本身对虚拟机运行没有什么用处,但是对于我们调试程序观察日志就有了帮助。LineNumberTable 存储的是Java源代码的行数 与 字节码行号的对应关系,这样当指定字节码出现异常后,就可找到对应出错的源代码行号快速定位问题,并且打印的堆栈异常中也可以看见具体是哪一行
指令讲解
对于一些指令比如上图可以看见有个sipush bipush, 这两个做的都是ipush工作
s 代表short类型 / b 代表byte类型
很多指令都是使用这种格式的比如 iconst , lconst 其中i为int , l 为 long, 所以下面的指令都是没有类型前缀了, 大家自己拼一下即可
这里列举下所有类型的对应关系
数据类型 | 前缀 |
---|---|
byte | b |
short | s |
int | i |
long | l (小写L) |
float | f |
double | d |
char | c |
引用类型 | a |
以下内容来自<<深入理解Java虚拟机>> 第三版第6章
加载存储
- load 将局部变量加载到操作数栈store 将一个数值从操作数栈存储到局部变量表const 将一个常量加载到操作数栈
运算
- add 加法sub 减法mul 乘法div 除法rem 求余neg 取反shr / shl 位移 or 按位或and 按位与xor 按位异inc 局部变量自增cmp / cmpg / cmpl 比较
对象创建 与访问
- new 创建类实例newarray 创建数组getfield putfield getstatic putstatic 访问类字段aload 将一个数组元素加载到操作数栈astore 将一个操作数栈的值储存到数组元素arraylength 获取数组长度instanceof checkcast 检查类实例类型
操作数栈管理
- pop / pop2 将操作数栈顶的一个或两个元素出栈dup dup2 dup_x1 dup2_x2.. 复制栈顶一个或两个数值并将复制值或双份的复制值重新压入栈顶swap 将栈顶端两个数值交换
控制转移
- if.. 条件分支tableswitch lookupswitch 复合条件分支goto goto_w jsr jsr_w ret 无条件分支
方法调用
- invokevirtual 调用对象实例方法invokeinterface 调用接口方法 在运行时会找到一个合适的实现了该接口方法的对象来调用invokespecial 调用一些需要特殊处理的实例方法(实例初始化方法, 私有方法, 父类方法)invokestatic 调用静态方法invokedynamic 用于运行时动态解析出调用点限定符所应用的方法