虚方法
可以被子类覆盖的方法称为虚方法。
虚方法调用
虚方法调用包括invokevirtual指令和invokeinterface指令。如果这两种指令所声明的目标方法被标记为final,那么JVM虚拟机会采用静态绑定。否则将采用动态绑定,根据调用者的动态类型来决定具体的目标方法。
方法表
动态绑定是通过方法表实现的。方法表中每一个重写方法的索引值与父类方法表中被重写的方法的索引值一致。
方法表本质上是一个数组,每个数组元素指向一个当前类及其祖先类中非私有的实例方法。方法表满足两个特质:1、子类方法表中包含父类方法表中的所有方法;2、子类方法在方法表中的索引值,与它所重写的父类方法的索引值相同。
在执行过程中,JVM将获取调用者的实际类型,在该实际类型的虚方法表中,根据索引值获得目标方法。
内联缓存
加快动态绑定的优化技术。它能够缓存虚方法调用中调用者的动态类型以及该类型所对应的目标方法。
单态:只缓存了一种动态类型以及该类型所对应的目标方法。
多台:缓存多个,需要逐个比较,如果命中,则调用对应的目标方法。
JVM只采用单态内联缓存。
内联缓存没有命中,需要使用方法表重新进行动态绑定。1、替换缓存中的值。在最坏的情况下,每次方法调用都要替换缓存,只有写缓存的额外开销,没有用缓存的性能提升。2、劣化为超多态。实际上是放弃优化,直接访问方法表,动态绑定目标方法,节省了写缓存的额外开销。