首页 > 代码库 > 方法调用指令
方法调用指令
在JDK7之前方法调用的字节码指令共有四条,invokeinterface、invokespecial、invokestatic、invokevirtual。由这四条指令完成Java中所有类型方法的调用。
操作数count是一个不为0的无符号数。objectref必须是一引用类型变量,在操作栈中,objectref后面必须跟随若干个参数值,这些参数值的数量,类型和顺序必须与解析出的接口方法描述符一致。第四个操作数的值必须为0。
假设objectref是类C引用变量,那么真正被调用的方法将按如下顺序进行查找:
a.如果类C声明了一个与接口方法的简单名称与描述符都相同的实例方法,那么这个实例方法被调用,查找程序结束。
b.否则,如果类C有父类,那么按照继承关系从下往上依次对C的各个父类进行第a步的搜索。
c.否则,虚拟机抛出一个AbstractMethodError错误。
如果被调用的方法含有synchronized修饰符,objectref的监视器会随着当前线程中monitorenter指令的执行而进入或重进行。如果被调用的方法不是本地方法,nargs参数值与objectref将一起从操作数栈中弹出,在Java虚拟机栈中将为该方法调用建立一个新的栈帧。objectref与参数值连续地放入新建栈帧的局部变量表中,objectref进入slot0,arg1进入slot1(如果arg1是long或者double类型的话,将占用slot1和slot2),依此类推。这时新建的栈帧成为当前栈帧,Java虚拟机的pc指向被调用方法的第一条字节码指令地址,紧接着就将执行方法的第一条指令。
如果被调用的方法是本地方法(native),如果这时实现该方法的具体平台的代码还没有绑定到Java虚拟机,那么就要去加载具体平台的代码进虚拟机。nargs参数值和objectref将从操作数栈中被弹出,并作为实现该本地方法代码的参数被传入,然后具体平台代码将以具体平台方式被调用。当平台代码执行完成返回时:
a.如果该本地方法含有synchronized修饰符,那么objectref关联的监视器在当前线程执行monitorexit指令后值被更新,如果监视器值变回0则退出。
b.如果该本地方法有返回值,那么该返回值在进行了具体实现相关的转换后被压入操作数栈。
连接异常:
在接口方法的符号引用解析过程中,任何有关接口方法解析的异常都可能被抛出。
运行时异常:
否则,如果objectref值为null,那么invokeinterface指令将抛出一个NullPointerException。
否则,如果objectref所在类没有实现被解析的接口,那么invokeinterface指令抛出IncompatibleClassChangeError错误。
否则,如果没有与简单名称和描述符都匹配的方法,那么invokeinterface将抛出AbstractMethodError。
否则,如果被选择的方法不是public的,invokeinterface将抛出IllegalAccessError错误。
否则,如果被选择的方法是abstract的,invokeinterface将抛出AbstractMethodError错误。
否则,如果被选择的方法是native的并且其本地实现方法没找到,nvokeinterface将抛出UnsatisfiedLinkError错误。
invokeinterface指令的count操作数记录了被选择方法的参数值数量,如果参数类型是long或double,那么该参数将按两个单位进行计算,其它任何参数类型按一个单位进行计算。第4个操作数在Oracle的Java虚拟机实现中使用,用于在运行时使用专门的伪指令替换掉invokeinterface指令,但它必须保证向前兼容。
接下来,被解析的方法要能被选中执行,必须满足以下所有条件:
a.当前类的访问标记中设置了ACC_SUPER标记(为1)
b.被解析方法所属类是当前类的父类
c.被解析方法不是实例初始化方法“<init>”(虽然实例初始化方法是由invokespecial指令调用,但其在当前类的初始化阶段就已经被执行完成,被初始化过的类是不能再执行类初始化方法的)
如果以上条件都成立,那么真正被执行的方法将按如下顺序行进选择。假设C是当前类的直接父类:
1.如果类C声明了一个与被解析方法简单名称与描述符都相同的实例方法,那么该被将被调用,查找程序结束。
2.否则,如果类C还有父类,那么按照继承关系从下往上依次对C的父类进行第1步的搜索。
3.否则,虚拟机抛出一个AbstractMethodError错误。
其它行为,如建立新的栈帧,参数入局部变量表,解析异常,运行时异常等与invokeinterface指令类似。
其它行为,如建立新的栈帧,参数入局部变量表,解析异常,运行时异常等与invokeinterface指令类似。
invokeinterface(调用接口方法)
操作数count是一个不为0的无符号数。objectref必须是一引用类型变量,在操作栈中,objectref后面必须跟随若干个参数值,这些参数值的数量,类型和顺序必须与解析出的接口方法描述符一致。第四个操作数的值必须为0。
假设objectref是类C引用变量,那么真正被调用的方法将按如下顺序进行查找:
a.如果类C声明了一个与接口方法的简单名称与描述符都相同的实例方法,那么这个实例方法被调用,查找程序结束。
b.否则,如果类C有父类,那么按照继承关系从下往上依次对C的各个父类进行第a步的搜索。
c.否则,虚拟机抛出一个AbstractMethodError错误。
如果被调用的方法含有synchronized修饰符,objectref的监视器会随着当前线程中monitorenter指令的执行而进入或重进行。如果被调用的方法不是本地方法,nargs参数值与objectref将一起从操作数栈中弹出,在Java虚拟机栈中将为该方法调用建立一个新的栈帧。objectref与参数值连续地放入新建栈帧的局部变量表中,objectref进入slot0,arg1进入slot1(如果arg1是long或者double类型的话,将占用slot1和slot2),依此类推。这时新建的栈帧成为当前栈帧,Java虚拟机的pc指向被调用方法的第一条字节码指令地址,紧接着就将执行方法的第一条指令。
如果被调用的方法是本地方法(native),如果这时实现该方法的具体平台的代码还没有绑定到Java虚拟机,那么就要去加载具体平台的代码进虚拟机。nargs参数值和objectref将从操作数栈中被弹出,并作为实现该本地方法代码的参数被传入,然后具体平台代码将以具体平台方式被调用。当平台代码执行完成返回时:
a.如果该本地方法含有synchronized修饰符,那么objectref关联的监视器在当前线程执行monitorexit指令后值被更新,如果监视器值变回0则退出。
b.如果该本地方法有返回值,那么该返回值在进行了具体实现相关的转换后被压入操作数栈。
连接异常:
在接口方法的符号引用解析过程中,任何有关接口方法解析的异常都可能被抛出。
运行时异常:
否则,如果objectref值为null,那么invokeinterface指令将抛出一个NullPointerException。
否则,如果objectref所在类没有实现被解析的接口,那么invokeinterface指令抛出IncompatibleClassChangeError错误。
否则,如果没有与简单名称和描述符都匹配的方法,那么invokeinterface将抛出AbstractMethodError。
否则,如果被选择的方法不是public的,invokeinterface将抛出IllegalAccessError错误。
否则,如果被选择的方法是abstract的,invokeinterface将抛出AbstractMethodError错误。
否则,如果被选择的方法是native的并且其本地实现方法没找到,nvokeinterface将抛出UnsatisfiedLinkError错误。
invokeinterface指令的count操作数记录了被选择方法的参数值数量,如果参数类型是long或double,那么该参数将按两个单位进行计算,其它任何参数类型按一个单位进行计算。第4个操作数在Oracle的Java虚拟机实现中使用,用于在运行时使用专门的伪指令替换掉invokeinterface指令,但它必须保证向前兼容。
invokespecial(调用私有方法,父类方法,类实例构造器)
接下来,被解析的方法要能被选中执行,必须满足以下所有条件:
a.当前类的访问标记中设置了ACC_SUPER标记(为1)
b.被解析方法所属类是当前类的父类
c.被解析方法不是实例初始化方法“<init>”(虽然实例初始化方法是由invokespecial指令调用,但其在当前类的初始化阶段就已经被执行完成,被初始化过的类是不能再执行类初始化方法的)
如果以上条件都成立,那么真正被执行的方法将按如下顺序行进选择。假设C是当前类的直接父类:
1.如果类C声明了一个与被解析方法简单名称与描述符都相同的实例方法,那么该被将被调用,查找程序结束。
2.否则,如果类C还有父类,那么按照继承关系从下往上依次对C的父类进行第1步的搜索。
3.否则,虚拟机抛出一个AbstractMethodError错误。
其它行为,如建立新的栈帧,参数入局部变量表,解析异常,运行时异常等与invokeinterface指令类似。
invokestatic(调用类、静态方法)
其它行为,如建立新的栈帧,参数入局部变量表,解析异常,运行时异常等与invokeinterface指令类似。
invokevitual(调用虚方法)
方法调用指令
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。