【响应式编程-03】Lambda表达式底层实现原理

一、简要描述

  • Lambda的底层实现原理
  • Lambda表达式编译和运行过程

二、Lambda的底层实现原理

  • Lambda表达式的本质

        函数式接口的匿名子类的匿名对象

  • 反编译:cfr-0.145.jar

        反编译:LambdaMetafactory.metafactory()

        跟踪调试,转储Lambda类:

                jdk.internal.lambda.dumpProxyClasses

                LambdaPrinciple$Lambda$1.class

  • 结论

        Lambda底层用匿名内部类实现:ASM技术

        Lambda表达式是个语法糖

【响应式编程-03】Lambda表达式底层实现原理_第1张图片

三、Lambda表达式编译和运行过程

  • JVM参数:jdk.internal.lambda.dumpProxyClasses
    • 命令java -Djdk.internal.lambda.dumpProxyClasses ClassName
    • 转储得到内部类ClassName$$Lambda$1.class
    • 反编译java -jar cfr-0.145.jar LambdaPrinciple.class --decodelambdas false
  • 本质:函数式接口的匿名子类的匿名对象

        Lambda表达式与函数接口的抽象函数格式一一对应

【响应式编程-03】Lambda表达式底层实现原理_第2张图片

1、LambdaPrinciple 代码实现

package tech.flygo.lambda.demo4;

import java.util.Arrays;
import java.util.List;

/**
 * Lambda表达式的底层实现
 * 语法:
 * (parameters) -> { statements; }
 * 或
 * (parameters) -> expression
 *
 * 

* JVM参数:jdk.internal.lambda.dumpProxyClasses * 命令:java -Djdk.internal.lambda.dumpProxyClasses ClassName * 转储得到内部类:ClassName$$Lambda$1.class * 反编译:java -jar cfr-0.145.jar LambdaPrinciple.class --decodelambdas false *

* 本质:函数式接口的匿名子类的匿名对象 * Lambda表达式与函数接口的抽象函数格式一一对应 */ public class LambdaPrinciple { public static void main(String[] args) { List stringList = Arrays.asList("one", "two", "three"); // 通过lambda表达式实现元素遍历 stringList.forEach(s -> { System.out.println(s); }); } }

2、cfr工具包解码Lambda代码实现

CFR解析包

cfr-0.145.jaricon-default.png?t=N7T8https://www.yuque.com/attachments/yuque/0/2023/jar/1509175/1684030971197-5456d0f4-1c6a-45d0-bf96-009ee00cd9cd.jar

2.1、复制cfr工具包到class目录下

【响应式编程-03】Lambda表达式底层实现原理_第3张图片

2.2、使用Java命令解码Lambda代码实现

  • 进入class目录
  • class和工具包同一级目录
  • 使用java命令解码Lambda实现内容

   java -jar cfr-0.145.jar LambdaPrinciple.class --decodelambdas false

【响应式编程-03】Lambda表达式底层实现原理_第4张图片

2.3、解码出来的Lambda内容

/*
 * Decompiled with CFR 0.145.
 */
package tech.flygo.lambda.demo4;

import java.io.PrintStream;
import java.lang.invoke.LambdaMetafactory;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class LambdaPrinciple {
    public static void main(String[] args) {
        List stringList = Arrays.asList("one", "two", "three");
        stringList.forEach((Consumer)LambdaMetafactory.metafactory(null, null, null, (Ljava/lang/Object;)V, lambda$main$0(java.lang.String ), (Ljava/lang/String;)V)());
    }

    private static /* synthetic */ void lambda$main$0(String s) {
        System.out.println(s);
    }
}

3、分析Lambda实现逻辑

3.1、LambdaMetafactory.metafactory()方法

从下面的源码可以看出,Java是严格遵循的面向对象原则,这里返回的是一个对象,而不是一个函数体。

【响应式编程-03】Lambda表达式底层实现原理_第5张图片

3.2、调用InnerClassLambdaMetafactory

【响应式编程-03】Lambda表达式底层实现原理_第6张图片

【响应式编程-03】Lambda表达式底层实现原理_第7张图片

3.3、InnerClassLambdaMetafactory.buildCallSite()构造调用点

【响应式编程-03】Lambda表达式底层实现原理_第8张图片

3.4、调用InnerClassLambdaMetafactory.spinInnerClass()

【响应式编程-03】Lambda表达式底层实现原理_第9张图片

【响应式编程-03】Lambda表达式底层实现原理_第10张图片

4、使用Java命令打开dumps调试模式

Java命令java -Djdk.internal.lambda.dumpProxyClasses ClassName

打开调试模式

4.1、进入class文件包文件的目录

特别注意:比如class文件的包路径为 tech.flygo.lambda.demo4,则进入目录 tech的上一级目录

执行java命令:java -Djdk.internal.lambda.dumpProxyClasses tech.flygo.lambda.demo4.LambdaPrinciple

【响应式编程-03】Lambda表达式底层实现原理_第11张图片

【响应式编程-03】Lambda表达式底层实现原理_第12张图片

4.2、查看Lambda生成的匿名内部类

【响应式编程-03】Lambda表达式底层实现原理_第13张图片

5、Java对动态语言的支持

使用javap查看class字节码:javap -p -v LambdaPrinciple

Java7之后增加了动态指令InvokeDynamic,Java支持动态语言

【响应式编程-03】Lambda表达式底层实现原理_第14张图片

【响应式编程-03】Lambda表达式底层实现原理_第15张图片

你可能感兴趣的:(MCA,开发语言,java,Lambda,Stream,响应式编程)