invokedynamic指令
在前面java动态类型语言支持(一)(二)中我们有提到invokedynamic指令和java.lang.invoke包中的MethodHandle机制,在某种程度上他们的作用是一样的,都是为了解决原有4条invoke*指令方法分派规则固话在虚拟机之中的问题,把如何查找目标方法的决定权从虚拟机转嫁到具体用户代码中,让yoghurt有更高的自由度。
每一处含有invokedynamic指令的位置都称作“动态调用点”,这条指令的第一个参数不再是代表方法符号引用的CONSTANT_Method_info常量,而是变为JDK新加入的CONSTANT_InvokeDynamic_info常量,从这个新常量中可以得到三项信息:引导方法(Bootstrap Method,此方法存放在新增的BootstrapMethods属性中)、方法类型(MethodType)和名称。引导方法是固有的参数,并且返回值是java.lang.invoke.Callsite对象,这个代表真正要执行的目标方法调用。根据CONSTANT_InvokeDynamic_info常量中提供的信息,虚拟机可以找到并执行应到方法,从而获得一个Callsite对象,最终调用要执行的目标方法。
掌控方法分派规则
invokedynamic指令与前面4条“invoke*”指令最大差别就是他的分派逻辑不是由虚拟机决定的,而是与程序员决定的。我们看如下代码:
我们思考在TODO处填入适当代码(不能修改其他地方的代码)实现调用祖父类的thinking方法。。
在java中我们可以通过super关键字很方便的调用到父类中的方法,如果要访问祖父类的方法在JDK1.7以前我们使用纯粹的java语言很难实现这个问题,原因在于Son类的thinking()方法中无法获取一个实际类型是GrandFather的对象引用,而invokevirtual指令的分派逻辑就是按照方法接收者的实际类型进行分派,这个逻辑是固化在虚拟机中的,程序员无法改变。在JDK1.7以后我们可以使用如下方式解决这个问题,代码如下: