我们都知道Java字节码是JVM所使用的指令集。java字节码可以分为如下几类:
操作数栈
Java 方法的栈桢分为操作数栈和局部变量区。通常来说,程序需要将变量从局部变量区加载至操作数栈中,进行一番运算之后再存储回局部变量区中。操作数栈的指令有如下:
-
dup 复制栈顶元素(常用于复制 new 指令所生成的未经初始化的引用。)如下代码生所的字节码:
-
pop 指令常用于舍弃调用指令的返回结果。当调用了有返回值的方法却不用返回值时需要有个pop指定,如下图所示:
- iconst,lconst, fconst, dconst, aconst, bipush, sipush,可以将不同类型的常量加载到操作数栈中。这几个指令的操作范围与类型如下表:
指令 | 类型 | 范围 |
---|---|---|
iconst | int(boolean, byte, char, short) | [-1, 5] |
lconst | long | 0, 1 |
fconst | float | 0, 1,2 |
dconst | double | 0, 1 |
dconst | reference | null |
bipush | int(boolean, byte, char, short) | [-128,127] |
sipush | int(boolean, byte, char, short) | [-32768,32767] |
-
ldc 加载常量池中的常量值。
将局部变量区的值加载到操作数栈的指令
Java 虚拟机将局部变量区当成一个数组,依次存放 this 指针(仅非静态方法),所传入的参数,以及字节码中的局部变量。存储在局部变量区的值,通常需要加载至操作数栈中,方能进行计算,得到计算结果后再存储至局部变量数组中。这些加载、存储指令如下表所示:
类型 | 加载指令 | 存储指令 |
---|---|---|
int(boolean, byte, char, short) | iload | istore |
long | lload | lstore |
float | fload | fstore |
double | dload | dstore |
reference | aload | astore |
-
iinc M, N指令,(其中 M为正整数,N为整数),用于操作局部变量区。表求的含义为:将局部变量数组的第 M 个单元中的 int 值增加 N,常用于 for 循环中自增量的更新。字节码如下图所示:
Java 相关指令
- new: 后跟目标类,生成该类的未初始化的对象。
-
instanceof:后跟目标类,判断栈顶元素是否为目标类 / 接口的实例。是则压入 1,否则压入 0。如图所示:
- checkcast:后跟目标类,判断栈顶元素是否为目标类 / 接口的实例。如果不是便抛出异常
- athrow:将栈顶异常抛出
-
monitorenter/monitorexit 为栈顶对象加解锁。如下图所示:
- getstatic、putstatic用于访问静态字段。
-
getfield、putfield用于访问实例子段。
数组相关指令
- newarray:新建基本类型数组。
- anewarray:新建引用类型数组
- multianewarray :生成多维数组
- arraylength: 求数组的长度。
数组相关的加载与存储指令如下表:
类型 | 加载指令 | 存储指令 |
---|---|---|
byte(boolean) | baload | bastore |
char | caload | castore |
short | saload | sastore |
int | iaload | iastore |
long | laload | lastore |
float | faload | fastore |
double | daload | dastore |
reference | aaload | aastore |
返回值相关指令
根据不同的返回类型,有不同的指令。如下表所示:
返回类型 | 返回指令 |
---|---|
void | return |
int(boolean, byte, char, short) | ireturn |
long | lreturn |
float | freturn |
double | dreturn |
reference | areturn |
其它
- goto:无条件跳转指令
-
tableswitch 和 lookupswtich:tableswitch针对密集的 cases,lookupswtich针对稀疏的 cases。