JVM字节码文件结构深度剖析
常量池类型分类
字节码文件
什么是魔数
- 字节码文件的前4个字节CAFEBABE
常量池
-
字面量: 指赋予成员变量的值,例如:String s = "hello","hello"就是字面量
- 文本字符串
- final的常量值
- 基本数据类型值
- 其他
-
符号引用: 指类中方法的名称
- 类和接口的全类名
- 字段的名称和描述符
- 方法的名称和描述符
字节码文件结构
- 魔数
- 主次版本号
- 常量池计数
- 本类索引
- 父类索引
- 接口计数
- 字段计数
- 方法计数
- 属性计数
常见问题
class文件组成
- class字节码文件由魔数、主次版本号、常量池、类信息、类的构造方法、类的中的方法信息、类变量与成员变量等信息组成
为什么我们在实例方法中可以调用this
- this在编译的时候,会被
作为第一个入参,也就是一个隐式入参放到局部变量表的第一个位置,即使构造方法没有参数,也会占用一个位置
如何定位到我们异常的代码
- JVM会维护一个
LineNumberTable,对应的字节码和代码会通过这个来维护,所以会通过这个来定位
解释下字节码里面加载和存储指令是什么
-
用于将数据再栈帧中的局部变量表和操作数栈之间来回传输,这类指令包括
-
将一个局部变量加载到操作数栈
- iload、iload_
- lload、lload_
- fload、fload_
- dload、dload_
- sload、sload_
-
将一个数值从操作数栈存储到局部变量表
- istore、istore_
- lstore、lstore_
- fstore、fstore_
- dstore、dstore_
- astrore、astore_
-
将一个常量加载到操作数栈
- bipush、sipush、idc、idc_w、idc2_w、aconst_null、iconst_m1、iconst、lsconst 、fconst、dconst_
-
扩充局部变量表的访问索引
- wide
-
解释下字节码里面方法调用指令有哪些
- invokevirtual: 用于调用对象的实例方法,根据对象的实际类型进行分派(虚拟方法派),这也是Java语言中最常见的方法分派方式
- Invokeinterface: 用于调用接口方法,它会在运行时搜索一个实现了这个接口方法的对象,找出适合的方法进行调用
- Invokespecial: 用于调用一些需要特殊处理的实例方法,包括实例初始化方法、私有方法和父类方法
- Invokestatic: 用于调用静态类方法
- Invokedynamic: 用于在运行时动态解析出调用点限定符所引用的方法,并执行该方法,前面4条指令的反派逻辑都固化在Java虚拟机内部,而invokedynamic指令的分派逻辑是由用户所设定的引导方法决定的,方法调用时用指令与数据类型无关