指令 参数 解释
checkcast | class | 校验类型转换,校验未通过将抛出ClassCastException |
getfield | class/field desc | 获取指定类的实例域,并将其值压入栈顶 |
getstatic | class/field desc | 获取指定类的静态域,并将其压入栈顶 |
instanceof | class | 检验对象是否是指定的类的实例,如果是,则将1压入栈顶,否则将0压入栈顶 |
new | class | 创建一个对象,并将其引用值压入栈顶 |
示例代码:checkcast:
Map<String, Object> map = new HashMap<>();
map.put("lt", liuzheTest);
LiuzheTest ts = (LiuzheTest) map.get("lt");
getfield:
public int getT() {
return t;
}
instanceof:if (o instanceof LiuzheTest)
与方法相关的JVM指令:
指令 | 操作数 | 解释 |
invokeinterface | class/method desc | 调用接口方法 |
invokespecial | class/method desc | 调用超类构造方法、实例初始化方法或私有方法 |
invokestatic | class/method desc | 调用静态方法 |
invokevirtual | class/method desc | 调用实例方法 |
pop:从当前栈顶出栈一个元素。
pop2:从栈顶的一个long或double类型的或两个其他数据从栈顶弹出
swap:将栈顶两个非long或者double类型的数值交换
指令 | 操作数 | 解释 |
aload | n | 将当前本地变量n放入栈顶中,变量n是一个引用,如aload_1,aload_2,aload_3 |
astore | n | 将栈顶元素存入本地变量n中,变量n是一个引用 |
dload | n | 将当前本地变量n放入栈顶中,变量n是一个double类型 |
dstore | n | 将栈顶元素存入本地变量n中,变脸n是一个double类型 |
fload | n | 将当前本地变量n放入栈顶中,变量n是一个fload类型 |
fstore | n | 将栈顶元素存入本地变量n中,变量n是一个float类型 |
iinc | n increment | 将指定int型变量增加指定值 |
iload | n | 将当前本地变量n放入栈顶中,变量n是一个int类型 |
lload | n | 将当前本地变量n放入栈顶中,变量n是一个long类型 |
istore | n | 将栈顶元素存入本地变量n中,变量n是一个long类型 |
3.与运算相关
6.与java数据类型转换相关
7.与java同步操作相关
指令 | 操作数 | 解释 |
monitorenter | 获得对象的锁,用于同步方法或同步块 | |
monitorexit | 释放对象的锁,用于同步方法或同步块 |
8.与java数组操作相关:
class字节码文件,通过javap -v 可以打印class字节码。这个就不演示了。不过在生成的字节码中,有两个地方需要解释一下:
一个是LineNumberTable,另一个是LocalVariableTalbe。
LineNumberTable
在LineNumberTable下面包含多个line a:b,每个line表示这个方法中的一行。其中a表示的是在这个方法中的一行代码在这个类文件中的第几行,而b是指这行代码的第一条JVM指令的pc偏移量。如在上面的main方法中有两行代码,
LocalVariableTable
LineNumberTable包含5个属性,分别是Start,Length,Slot,Name和Signature。其中,Start和Length表示该变量的有效作用域的偏移地址;Start表示该变量被赋值到某个Slot中的指令(xstore_x指令)的下一条指令的偏移地址:Length表示该变量作用域总共占用的指令数对应的偏移量,所以一个变量的作用域就是[Start,Start+Length];Slot和Name分别表示该变量占用的Slot编号和该变量的名称,Signature表示该变量的类型。下面结合一个例子再介绍以下它们的含义。
上图对应的字节码和LineNumberTable如下:
在这个方法中有6个变量,共使用了4个Slot。变量j在lstore4这条指令中被首次赋值,所以它的Start从下一条指令开始,也就是iinc 3 -1指令的偏移量是21,而Length是3,说明这个变量的作用域是[21,24],偏移量24对应的指令是goto14,从源码看变量j的有效范围与在while循环体内是吻合的。
从上面的LocalVariableTalbe中还能发现,变量i和b使用的都是Slot3,它们为什么能公用Slot区?变量i的作用域是[14,27],变量b的作用域是[33,40],可以发现它们的作用域是不重合的,而Slot的使用规则正是当变量作用域不重合时可以重复使用。这也解释了为什么有6个本地变量,但是实际上只使用了4个Slot。