Lambda 在 JVM 里到底是什么?这篇用 javap 看字节码、用对象比较和类信息看运行时形态、用类加载日志看首次链接的代价(方法引用的四种形式、LambdaMetafactory 的直接调用在后面的篇目)。
out 目录下的 .class 文件: ['Main$1.class', 'Main.class'] (匿名内部类 Main$1 有独立的 class 文件,lambda 没有)
main 里的 invokedynamic 指令:
0: invokedynamic #7, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable;
6: invokedynamic #11, 0 // InvokeDynamic #1:apply:()Ljava/util/function/Function;
16: invokedynamic #15, 0 // InvokeDynamic #2:run:(I)Ljava/lang/Runnable;
编译器生成的私有合成方法:
private static void lambda$main$2(int);
private static java.lang.Integer lambda$main$1(java.lang.Integer);
private static void lambda$main$0();
BootstrapMethods 里的引导方法: ['metafactory'] (三个 lambda 都用 LambdaMetafactory.metafactory)不捕获变量的 lambda,同一个位置求值 3 次:non[0]==non[1] true,non[1]==non[2] true 捕获了变量 k 的 lambda,同一个位置求值 3 次:cap[0]==cap[1] false,cap[1]==cap[2] false 两个写法完全相同、但在不同位置的 lambda:x==y false,x.getClass()==y.getClass() false
getClass().getName() = Main$$Lambda/0x… isSynthetic = true,isHidden = true,实现的接口 = [interface java.lang.Runnable],父类 = java.lang.Object Class.forName(类名) → ClassNotFoundException(隐藏类不能按名字加载) 声明的方法 = [run]
第一个 lambda 位置第一次求值(含 invokedynamic 链接):3021 µs;第二个位置:149 µs(这里夹着 s1.get 的调用);第三个位置:143 µs 同一个位置再求值 1000 次:平均 289 ns/次 (另外两次独立运行:) 2895 µs 3163 µs 加载的类数:什么都不做 441;只用 1 个 lambda 531(多 90 个);只用 1 次字符串 +(也是 invokedynamic)527(多 86 个);identity 模式(4 个 lambda 位置 + 字符串拼接)560(多 119 个)