一 字节码与数据类型
大部分的指令都包含了其操作所对应的数据类型信息。
比如iload指令用于从局部变量表中加载int类型的数据到操作栈中,而fload指令加载的则是float数据类型的数据。
二 加载与存储指令
主要用于将数据在栈帧的局部变量表和操作数栈之间来回传输。
将局部变量表加载到操作数栈:
iload,lload,fload,dload,aload(引用类型)
将一个数值从操作数栈存储到局部变量表:
istore,lstore,fstore,dstore,astore
将一个常量加载到操作数栈:
bipush,sipush,iconst,lconst,fconst,dconst,aconst,ldc,ldc_w,ldc2_w,aconst_null
扩充局部变量表的访问索引的指令:
举个例子:
对于这个样的类的方法:
public class MessageQueue implements Serializable{
publicint mutiply (int a, int b) {
returna * b;
}
}
首先是将参数a,b肯定都是在局部变量表中,利用iload_1指令和iload_2指令,加载到操作数栈,然后进行imul操作,最后将结果返回ireturn。
为什么有2各参数,但是字节码却显示三个,那是因为还有默认的this
三 运算指令
加法指令:iadd ladd fadddadd
减法指令:isub lsub fsubdsub
乘法指令:imul lmul fmuldmul
除法指令:idiv ldiv fdivddiv
求余指令:irem lrem fremdrem
取反指令:ineg lneg fnegdneg
比较指令:dcmpg dcmlpfcmpg fcmlp lcmp
局部变量表自增:iinc
四 类型转换指令
可以将2种不同类型的数值,这些转换操作一般用于实现用户代码中显示类型转换操作;另外一个就是字节码只有256个,每一个数据类型都对应一个字节码指令,肯定不够分,所以有时候需要借助类型转换指令进行转换
宽化类型转换(向上转型):都是比较安全的,不需要使用字节码
窄话类型转换(向下转型):必须显示使用转换指令:i2b,i2c,i2s,f2i,
f2l,d2i,d2l,d2f等
public class TypeConvert implements Serializable{
publicint convert (float a) {
intb = (int)a;
returnb;
}
}
五 对象创建与访问指令
创建类实例指令:new
创建数组指令:newarrayanewarray multianewarray
访问类字段:getfieldputfield,getstatic,putstatic
把数组元素加载到操作数栈:baload caload saloadiaload laload faload daload aaload
将一个操作数栈的值存储到数组元素指令:bastorecastore sastore iastore lastore fastore dastore aastore
取数组长度指令: arraylength
检查类实例类型指令:instanceof checkcast
六 操作数栈指令
将操作数栈的栈顶一个或者两个元素出栈:pop pop2
复制栈顶一个或者两个数值并将复制值重新压入栈顶:dup,dup2,dup_x1,dup2_x1等
将栈顶最顶端2个值互换:swap
七 控制转移指令
就是让JAVA虚拟机有条件的或者无条件从指定的位置指令的下一条指令继续执行,而不是从控制指令的下一条指令继续执行。比如条件控制。
条件分之:ifeq iflt ifgtifne ifnull ifcmple
复合条件分之:tablesswitchlookupsswitch
无条件分之:goto goto_wjsr_w ret
public void execute(int a) {
if ( a %2 == 0)
System.out.println("偶数");
else
System.out.println("奇数");
}
八 方法调用和返回指令
invokevirtual: 调用对象实例方法,根据对象的实际类型进行分派
invokeinterface: 指令用于调用接口方法,它会在运行时搜索一个实现了这个接口的方法的对象,找出合适的方法进行调用。
invokestatic: 调用类方法
package com.test.jvm.model;
public class TypeConvet {
publicstatic void main(String[] args) {
Closablecloseable = new Connections();
closeable.close();
Booksbooks = new Books();
books.done();
}
}
interface Closable {
voidclose();
}
class Connections implements Closable{
@Override
public voidclose() {
//TODO Auto-generated method stub
}
}
class Books {
publicvoid done(){}
}
九 同步指令
Java虚拟机可以支持方法级的同步,和方法内部一段指令序列的的同步。
方法级的同步是隐式的,即无需通过字节码指令来控制,它实现在方法调用和返回操作之间,虚拟机可以从常量池的方法表结构method_info_structure中的ACC_SYNCHRONIZED访问标志区分一个方法是否同步。当方法调用时,调用指令将会检查ACC_SYNCHRONIZED是否被设置,如果设置了,执行线程将先持有Monitor,然后再执行方法,最后方法完成释放Monitor。
同步一段指令集序列通常是由synchronized块来表示的,JAVA虚拟机的指令集中有monitorenter和monitorexit两条指令来支持synchronized语义。