前面三篇讲了lambda
表达式的一些基本概念和核心类Stream
的基本操作,那么lambda
表达式的实现原理到底是怎么样的呢?
我们以前创建Runnable
的时候是用匿名内部类的方式实现,而有lambda
表达式之后,代码变得很简洁,很方便。代码如下:
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println();
}
};
Runnable r = () -> System.out.println();
所以对于lambda
表达式实现原理的直接想法就是通过创建匿名内部类实现的。事实到底如何呢?我们可以通过反编译的方式进行验证。
public class LambdaTest {
public static void output(String s, Function<String> fun) {
fun.out(s);
}
public static void main(String[] args) {
String str = "hello ";
output("world", x -> System.out.println(str + x));
}
}
@FunctionalInterface
interface Function<T> {
void out(T x);
}
通过cmd输入javap -p LambdaTest
,可以得到下面的信息:
Compiled from "LambdaTest.java"
public class cn.tl.test.LambdaTest {
public cn.tl.test.LambdaTest();
public static void output(java.lang.String, cn.tl.test.Function<java.lang.String>);
public static void main(java.lang.String[]);
private static void lambda$main$0(java.lang.String, java.lang.String);
}
跟原代码相比,多了一个私有静态方法lambda$main$0
。
执行代码的时候,我们还可以通过在IDEA上的VM options栏加上-Djdk.internal.lambda.dumpProxyClasses
,可以看到生成了一个类LambdaTest$$Lambda$1
。它是通过LambdaMetafactory
的metafactory
方法动态生成的。反编译代码如下:
final class LambdaTest$$Lambda$1 implements Function {
private final String arg$1;
private LambdaTest$$Lambda$1(String var1) {
this.arg$1 = var1;
}
private static Function get$Lambda(String var0) {
return new LambdaTest$$Lambda$1(var0);
}
@Hidden
public void out(Object var1) {
LambdaTest.lambda$main$0(this.arg$1, (String)var1);
}
}
通过以上的代码,也就可以看出不是通过匿名内部类实现的,而是通过内部类+私有静态方法
实现的。(为什么是内部类?因为调用了LambdaTest
类的私有静态方法lambda$main$0
。)
还有为什么lambda
表达式引用的局部变量不能改变的原因也显而易见,因为局部变量是final类型的,只不过声明的时候不用写final
关键字,而JDK8之前匿名内部类强制写final
关键字。因此最终的Lambda
表达式大概等价于以下形式:
public class LambdaTest {
public static void output(String s, Function<String> fun) {
fun.out(s);
}
public static void main(String[] args) {
String str = "hello ";
output("world", x -> System.out.println(str + x));
output("world", new LambdaTest().new LambdaTest$$Lambda$1(str));
}
//lambda表达式生成一个私有静态方法,表达式右边为方法体,涉及到的变量全部作为方法参数
private static void lambda$main$0(String arg0, String x) {
System.out.println(arg0 + x);
}
//函数式接口实现类,复写方法调用私有静态方法
final class LambdaTest$$Lambda$1 implements Function {
private final String arg$1;
private LambdaTest$$Lambda$1(String var1) {
this.arg$1 = var1;
}
//该方法报错不应该是static,功能暂时不明。
private static Function get$Lambda(String var0) {
return new LambdaTest$$Lambda$1(var0);
}
public void out(Object var1) {
LambdaTest.lambda$main$0(this.arg$1, (String) var1);
}
}
}
@FunctionalInterface
interface Function<T> {
void out(T x);
}