inDy(invokedynamic)是 java 7 引入的一条新的虚拟机指令,这是自 1.0 以来第一次引入新的虚拟机指令。到了 java 8 这条指令才第一次在 java 应用,用在 lambda 表达式中。 indy 与其他 invoke 指令不同的是它允许由应用级的代码来决定方法解析。所谓应用级的代码其实是一个方法,在这里这个方法被称为引导方法(Bootstrap Method),简称 BSM。BSM 返回一个 CallSite(调用点) 对象,这个对象就和 inDy 链接在一起了。以后再执行这条 inDy 指令都不会创建新的 CallSite 对象。CallSite 就是一个 MethodHandle(方法句柄)的 holder。方法句柄指向一个调用点真正执行的方法。
我对上面内容的解释,就是通过引导方法,创建相关的 methodHandle 执行环境,并组成 CallSite。然后等待字节码层面上的调用,也就是 inDy。
MethodHandle
一个 java 方法的实体有四个构成:
- 方法名
- 签名 — 参数列表和返回值
- 定义方法的类
- 方法体(代码)
Lambda 表达式 和 inDy
这里的主要方法和上文大同小异,但是核心是需要 1、创建匿名类并导入到 JVM 中。2、创建 CallSite
接下来就是执行 LambdaMetafactory.metafactory
方法了,它会创建一个匿名类,这个类是通过 ASM 编织字节码在内存中生成的,然后直接通过 unsafe 直接加载而不会写到文件里。不过可以通过下面的虚拟机参数让它运行的时候输出到文件
这个类是根据 lambda 的特点生成的,输出后可以看到,在这个例子中是这样的:
然后就是创建一个 CallSite,绑定一个 MethodHandle,指向的方法其实就是生成的类中的静态方法 LambdaTest$$Lambda$1.get$Lambda(String[])Runnable
。然后把调用点对象返回,到这里 BSM 方法执行完毕。