java中Lambda表达式的实现原理
简单使用
import java.util.function.Consumer;
public class TestLambda {
public static void main(String[] args) {
Consumer<String> consumer = System.out::println;
consumer.accept("hello");
}
}
反编译后字节码
getstatic #2 <java/lang/System.out>
dup
invokestatic #3 <java/util/Objects.requireNonNull>
pop
invokedynamic #4 <accept, BootstrapMethods #0>
astore_1
aload_1
ldc #5 <hello>
invokeinterface #6 <java/util/function/Consumer.accept> count 2
return
invokedynamic是Java 7为了实现在JVM上运行动态语言而引入的一条新的虚拟机指令,它可以实现在运行期动态解析出调用点限定符所引用的方法,
然后再执行该方法,invokedynamic指令的分派逻辑是由用户设定的引导方法决定。Lambda表达式的核心就是invokedynamic指令。
实现原理
通过debug可知,Lambda表达式最终是通过InnerClassLambdaMetafactory类来创建匿名内部类来实现的,使用ASM来创建匿名内部类
最后通过Unsafe(java提供的魔法类,可以操作底层资源)的defineAnonymousClass()方法来将字节数组转换成Class对象,
类似于ClassLoader的loadClass()方法的功能,但这种方法生成的匿名类不显式挂在任何ClassLoader下面,只要当该类没有存在的实例对象、
且没有强引用来引用该类的Class对象时,该类就会被GC回收。因此这种匿名内部类相比于Java语言层面的匿名内部类更容易回收。
通过匿名内部类的Class对象创建调用点CallSite
总结
在Lambda表达式实现中,通过invokedynamic指令调用引导方法生成调用点,在此过程中,会通过ASM动态生成字节码,
而后利用Unsafe的defineAnonymousClass方法定义实现相应的函数式接口的匿名类,然后再实例化此匿名类,
并返回与此匿名类中函数式方法的方法句柄关联的调用点;而后可以通过此调用点实现调用相应Lambda表达式定义逻辑的功能。