虚方法的调用
java里所有的非私有实例方法调用都会被编译成invokevirtual指令,接口方法调用都会被编译成invokeinterface指令,这两种指令,均属于java虚拟机中的虚方法调用。
在绝大多数的情况下,java虚拟机需要通过调用者的动态类型来确定虚方法调用的目标方法,这个过程我们称之为动态绑定。相对于静态方法的非虚方法调用来说,虚方法调用更加耗时。
java虚拟机中,静态绑定包括用于调用静态方法的invokestatic指令和用于调用构造器、私有实例方法以及超类非私有实例方法的invokespecial指令。如果虚方法调用指向一个标记为final的方法,那么java虚拟机也可以静态绑定该虚方法调用的目标方法。
Java 虚拟机采用了一种用空间换取时间的策略来实现动态绑定.它为每一个类生成一张方法表,用来快速定位目标方法。
方法表
熟悉类加载机制的你也许会知道,在类加载的准备阶段,除了为静态字段分配内存之外,还会构造与该类相关联的方法表,这个数据结构是jvm实现动态绑定的关键所在。
方法表本质上是一个数组,每个数组元素指向一个当前类以及其祖先类中非私有的实例方法。
这些方法可能是具体的可执行的方法,也可能是没有相应字节码的抽象方法。
方法表满足两个特质:
- 子类方法表中包含父类方法表中的所有方法
- 子类方法在方法表中的索引值,与它所重写的父类方法的索引值相同
java虚拟机中的动态绑定是通过方法表这一个数据结构实现的。方法表中的每一个重写方法的索引值,与父类方法表中被重写的方法的索引值一致。在解析虚方法调用的时候,java虚拟机会记录下所声明的目标方法的索引值,并且在运行过程中根据这个索引值查找到具体的目标方法。
java虚拟机的即时编译器会使用内联缓存来加速动态绑定.java虚拟机所采用的单态内联缓存将记录调用者的动态类型以及它所对应的目标方法。
当碰到新的调用者时,如果其动态类型与缓存中的类型相互匹配,则直接调用缓存中的目标方法。否则,java虚拟机将该内联缓存退化为超多态内联缓存,今后的执行过程中直接使用方法表进行动态绑定。
以上内容参考自极客时间郑雨迪老师<<深入拆解Java虚拟机>>的总结
网友评论