invokedynamic与lambda表达式

本文主要是探讨lambda表达式是如何被虚拟机执行的.

  • invokedynamic的执行

在虚拟机中,每条invokedynamic指令出现的位置,都称为一个动态调用点.该指令接受一个u2的参数,该参数指向常量池中的一个InvokeDynamic_info.
每个InvokeDynamic_info由两部分组成,分别是指向NameAndType以及指向BootStrapMethod的u2引用.
BootStrapMethod的组成如下

名称 用途
bootstrap_method_ref 指向常量池中的一个MethodHandler(mh),该mh必须指向一个能够返回CallSite对象的方法
num_bootstrap_arguments 启动参数个数
bootstrap_arguments 可以指向MethodHandler/Class/String/Float/Double; invokedynamic指令的动态性,在这里体现,通过传入不同的静态启动参数(可以为MethodHandler),动态的使用方法

MethodHandler_info的结构主要有两项,分别为reference_kind以及reference_index.其中reference_kind指向了方法的调用类型,reference_index指向了一个MethodRef(含有方法的声明class与NameAndType信息).

  • lambda表达式的翻译与执行
    1. 在使用表达式的类中生成对应的lambda方法,方法名类似于private static void lambda$main$0(int, int);
    2. invokedynamic指令对应的启动方法的bootstrap_method_ref指向了以下的MethodHandler.(invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;)
    3. 该启动方法接受6个参数,其中前三个由jvm生成,第二和第三个参数分别是由动态调用点的NameAndType(相应函数式接口的方法名与方法描述符)生成的.第四与第六个参数一般情况一致,代表了相应函数式接口的方法描述符.第五个参数最为关键,它是一个MethodHandler的引用,实际指向了用户实现的lambda方法(private static void lambda$main$0(int, int))
    4. invokedynamic先调用metafactory方法生成一个CallSite(在生成CallSite的之前,利用传进去的参数,特别是MethodHandler(lambda$main$0(int, int))以及外部的捕获运行值来生成一个临时类,该临时类实现了函数式接口),对该CallSite进行调用(内部对临时类使用反射构造一个实例),返回了一个函数式接口的实例对象.

你可能感兴趣的:(虚拟机,lambda)