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)

  • 运行时可变的方法引用
  • 如 ConstantCallSiteMutableCallSite

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 启动更快、内存更省的原因!