字节码指令
虚拟机指令是由一个字节的长度的代表着某种操作含义的操作码,以及后面跟上一个操作数。所以由操作码+操作数就构成了我们具体使用的一个指令。也不尽然,也会有一些特殊的操作码不含有操作数构成了一个指令。
字节码文件解读
Notepad++
Binary Viewer
Bytecode viewer
这个更高级一点,和我们在idea
安装的插件是一样的(Jclasslibe
),所以我们没必要再去单独安装一下,可以直接在idea
中使用javap -v *.class
可以使用Java
自带的Java解析工具来实现class
文件的解读
class 文件结构
- 魔术
Magic number
- 版本号
- 编译
jdk
的版本号
- 编译
- 常量池
- 字面量和符号引用
- 访问标识
- 对当前类的声明是什么(public、private…)
- 类索引、父类索引、实现的接口集合
- 字段表集合
- 方法表集合
- 属性表集合
字节码
加载与存储指令
# 从操作数栈中弹出元素放到局部变量 1 的位置
istore_1
# 压栈,表示从局部变量表压入到操作数栈中
xload_<n> (x 为 i、l、f、d、a、n,n 为 0 ~ 3)
xload (x 为 i、l、f、d、a)
# 常量入栈
const
push
- bipush(8 位整数)、sipush(16 位整数)
ldc (如果 const 和 push 都不可以满足需求则可以使用这个来处理)
算数运算
# 加法
iadd ladd fadd dadd
# 减法
isub lsub fsub dsub
# 乘法
imul lmul fmul dmul
# 除法
idix ldiv fdiv ddiv
# 求余
irem lrem frem drem
# 取反
ineg lneg fneg dneg
# 自增指令
iinc
# 比较指令
dcmpg dcmpl fcmpg fcmpl lcmp
# 位运算
# 位移指令
ishl sihr iushr lshl lshr lushr
# 按位或
ior lor
# 按位与
iand land
# 按位异或
ixor lxor
方法调用
invokevirtual
- 用于调用对象实例方法,根据对象的实际类型分派(虚方法分派),支持多态,这也是 Java 语言中最常见的方法分派方式
invokeinterface
- 用于调用接口方法,它会在运行时搜索由特定对象所实现的这个接口方法,并找到合适的方法进行调用
invokespecial
- 用于调用一些需要特殊处理的实例方法,包括初始化方法(构造器)、私有方法和父类方法。这些方法都是静态类型绑定的,不会在调用时进行动态分派
invokestatic
- 用于调用类中类方法(
static
修饰的方法)。这是静态绑定的
- 用于调用类中类方法(
invokedynamic
- 调用动态绑定的方法,这个是
JDK1.7
后加入的指令,用于在运行时动态解析出调用点限定符所引用的方法,并执行方法。前面四个方法的调用指令都固化在Java虚拟机
内部,而invokedynamic
指令的分派逻辑是由用户所设定的引用方法决定的
- 调用动态绑定的方法,这个是