某种程度上讲 invokedynamic指令和MethodHandle机制的作用是一样的,都是为了解决分派机制固化在虚拟机的特点,让用户有更高的自由度是其设计的目的。MethodHandle类似,只不过methodHandle采用Java语言和API进行实现,invokedynamic则是字节码来完成。
每一个含有invokedynamic指令的位置称为动态调用点dynamic Call site 这条指令的第一个参数不再是代表方法的符号引用,而是引入了新的常量,从这个常量可以获取的信息:引导方法(Bootstrap Method),此方法存放在新增的BootstrapMethods属性中,方法类型,和名称。引导方法是固有的参数,返回值是java.lang.invoke Callsite对象,这个代表真正执行的目标方法调用,虚拟机根据相关信息找到并执行引导方法,从而获得Call site对象,最终调用需要执行的目标方法
——方法分派规则
invokedynamic指令与其它4条invoke*指令的最大差别是它的分派逻辑不再由虚拟机决定,而是由程序员控制。
传统多层继承的问题:
class GrandFather
{
void think()
{
System.out.println("GrandFather");
}
}
class Father extends GrandFather
{
void think()
{
System.out.println("Father");
}
}
class son extends Father
{
void think()
{
//这里可以通过supre.think()调用直接父类Father的think方法
//但却不能调用到最终父类的GrandFather的think方法
}
}
son中调用不到GrandFather的think方法 因为无法获取到GrandFather的对象引用 ,而invokevirtual指令分派逻辑是按照方法接收者实际类型分派,这个逻辑受虚拟机控制,难以解决
——使用MethodHandle解决
class son extends Father
{
void think()
{
try
{
MethodType mt=MethodType.methodType(void.class);//返回值是void
//调用findup().findSpecial查找方法 参数列表 从哪儿找 方法名 返回类型
MethodHandle mh=MethodHandles.lookup().findSpecial(GrandFather.class, "think", mt, getClass());
mh.invoke(this);
}catch(Throwable e)
{
}
}
}
public class Test {
public static void main(String[] args) {
new son().think();
}
}
直接通过MethodHandle查找到GrandFather的think方法,并invoke执行