虚拟机层面的方法调用

我们知道java作为静态类型语言(编译期确定类型)直到java 8 之后才使用lambda表达式 对动态特性进行了代码层面的使用。虚拟机关于方法调用的指令有 invokestatic invokespecial invokevirtual invokeinterface,这些指令的第一个参数是在编译期间产生的符号引用,而动态语言是在运行期才能确定类型。那么java在虚拟机层面支持动态类型就成了java平台的发展趋势。java7 的java.lang.invoke 包来支持动态特性。之前我们的方法调用主要通过符号引用来确定调用的目标方法,而这个包为我们提供了一种新的动态确定目标方法的机制称为“method Handle”。类似于c++中的函数指针。在c++中我们可以把一个函数当做参数进行传递,而在java中则不行。
现在有了MethodHandle 就可以用类似的方式操作,
比如sort(int[] list,MethodHandle mh) 参数mh就可以是比较函数,代替了java中常用的java Arrays.sort(arr,Comparator comparator);那么如何操作呢?如下代码演示了如何在代码层面利用invoke包进行根据实际类型进行其方法调用。

public class Hello {
    static class ClassA{
        public void println(String s){
            System.out.println(s);
        }
    }
    public static void main(String[] args) throws Throwable {
       while(true){
           long time = System.currentTimeMillis();
           if (time % 2 == 0) {
               getMethodHandle(new ClassA()).invokeExact("gaojl hello!");
           } else {
               getMethodHandle(System.out).invokeExact("niub gaojl!");
           }
       }
    }
    public static MethodHandle getMethodHandle(Object rec) throws NoSuchMethodException, IllegalAccessException {
        MethodType mt = MethodType.methodType(void.class,String.class);

        MethodHandles.Lookup l = MethodHandles.lookup();
        return l.findVirtual(rec.getClass(),"println",mt).bindTo(rec);

    }
}

其实invokedynamic 指令与MethodHandle 机制的作用是一样的,都是为了解决原有的4条指令invoke*把分派逻辑固化在虚拟机层面,把如何查找目标方法的决定权从虚拟机转化到用户代码层面,让用户有更高的自由度。

二者思路目的是一致的:为了找到目的方法 invoke*4条指令利用符号引用 直接引用类来完成,而invokedynamic 是利用上层api来完成。

之前我们的invoke*指令的第一个参数 为常量池的方法符号引用,然后找到该线程对应的虚拟机栈中的操作数栈的栈顶元素,其实际类型记为C,之后按自己->父亲->…进行查找
invokedynamic 第一个参数为常量池中的CONSTANT_invokedynamic_info常量,从这个新常量中可以得到三种类型的信息:Bootstrap Method 、methodtype、方法名称。 值得注意的是bootstrap method方法返回的是CallSite 对象,这个代表真正要执行的方法调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值