Lambda 表达式不是匿名内部类!
误区:Lambda = 匿名类语法糖?
// 很多人以为 Lambda 等价于:
list.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}
});❌ 错!
真相:Lambda 通过 invokedynamic 实现
使用 javap -c -p YourClass.class 反编译:
// 编译后实际调用:
0: invokedynamic #2, 0 // CallSite bootstrap: java/lang/invoke/LambdaMetafactory.metafactory✅ Lambda 的创建被推迟到运行时,由
LambdaMetafactory动态生成实现类!
invokedynamic 核心机制:三大组件
1. 调用点(Call Site)
- 运行时可变的方法引用
- 如
ConstantCallSite、MutableCallSite
2. 引导方法(Bootstrap Method)
- 在
.class文件中定义 - 负责初始化
CallSite - Lambda 使用
LambdaMetafactory.metafactory()
3. 方法句柄(MethodHandle)
- JDK 7 引入,“强类型的反射”
- 比反射更快、更安全
// MethodHandle 示例
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findStatic(System.class, "currentTimeMillis", MethodType.methodType(long.class));
long time = (long) mh.invokeExact();✅
MethodHandle可被 JIT 优化,性能接近直接调用!
实战:Lambda 字节码分析
源码
public class LambdaDemo {public static void main(String[] args) {List<String> list = Arrays.asList("A", "B", "C");list.forEach(s -> System.out.println(s));}
}反编译结果(关键部分)
main([Ljava/lang/String;)V// ... 初始化 listaload_1invokedynamic #2, 0 // InvokeDynamic #0:accept:()Ljava/util/function/Consumer;invokevirtual List.forEach(Ljava/util/function/Consumer;)Vreturn// 引导方法
BootstrapMethods:0: #27 invokestatic java/lang/invoke/LambdaMetafactory.metafactoryMethod arguments:#28 MethodType interface java/util/function/Consumer.accept:(Ljava/lang/Object;)V#30 invokestatic LambdaDemo.lambda$main$0:(Ljava/lang/String;)V#28 MethodType interface java/util/function/Consumer.accept:(Ljava/lang/Object;)V📌 解读:
invokedynamic调用LambdaMetafactory.metafactory- 引导方法返回一个
CallSite,指向lambda$main$0静态方法 - Lambda 实例在运行时生成,不生成
.class文件(默认)
✅ 这就是 Lambda 启动更快、内存更省的原因!