Java8新特性--Lambda表达式究竟做了什么?让我们一探究竟

🥇前言

大家好啊,我是爷爷的茶七里香,大家经常使用Lambda表达式,那有没有好奇它都做了什么呢?今天就让我们来一起探究探究吧!

🥇开篇

先上一个🌰

package xyz.keydoisdls.mybatisplus.test;

public class MyTest {
    // 定义了一个接口
    interface TestInterface {
        void m1();
    }

    // 定义了一个函数 接收一个TestInterface
    public static void testMethod(TestInterface testInterface) {
        // 调用TestInterface的m1方法
        testInterface.m1();
    }

    // 主函数
    public static void main(String[] args) {
        // 匿名内部类写法
        testMethod(new TestInterface() {
            @Override
            public void m1() {
                System.out.println(" ---------匿名内部类写法执行了------- ");
            }
        });

        // Lambda表达式写法
        testMethod(() -> {
            System.out.println(" ---------Lambda表达式写法执行了------ ");
        });
    }

}

看上述代码,Lambda表达式相较于匿名内部类来说简化了不少是吧,在编译的时候匿名内部类会有个字节码文件生成,那么Lambda表达式是怎么样的呢?让我们来一探究竟!

先运行起来先,结果如下,接下来我们需要找到存放字节码文件的目录!!!

字节码文件如下:

在这之前呢,先给大家介绍一个可视化界面的反编译工具--jadx

jadx下载地址:https://github.com/skylot/jadx/releases/download/v1.3.1/jadx-gui-1.3.1-with-jre-win.zip

jadx源码仓库地址:

https://github.com/skylot/jadx/tree/v1.3.1

下载下来后直接运行jadx-gui-1.3.1.exe就行,然后把你要反编译的字节码文件拖入到软件当中:

 下面我们分别对三个class文件反编译看下里面的内容:

  • MyTest$1.class(匿名内部类生成的字节码文件)

  •  MyTest$TestInterface.class(接口对应的字节码文件)

  • MyTest.class(存在主函数的类对应字节码文件) 

通过以上的反编译,我们已经知道了哪个字节码文件对应的是哪部分的了;那么通过反编译我们可以看到匿名内部类抽出来了,生成了一个独立的class文件,匿名内部类对应的位置变成了new 1();这个是什么呢?MyTest$1.class是匿名内部类的字节码文件,而这个new 1()中的1指的就是字节码文件名中$符号后面的1;这样看来匿名内部类做了哪些操作我们就知道了,但我们还是不知道Lambda表达式做了什么,我们接着往下看:

 我们需要借助JDK自带的一个工具--javap(该工具可以对字节码文件反汇编)

javap -c -p 类名.class
  • -c:对代码进行反汇编
  • -p:显示所有类和成员

 让我们直接对存在lambda表达式的字节码进行反汇编看下结果:

 注意看上面绿框部分,我并没有书写这部分的代码,但是我反汇编之后出现了这部分代码,说明这是lambda搞的鬼,那么问题来了,这个lambda$main$0()方法,它是什么时候被调用的?我在主函数中也没有找到与之相关的关键字。不着急,咱们接着往下看:

接下来我们需要使用java命令去运行包含主函数的字节码文件,并且需要加一个参数:

java -Djdk.internal.lambda.dumpProxyClasses 包名.类名
  •  -Djdk.internal.lambda.dumpProxyClasses:加了这个参数可以将运行时生成的字节码单独抽出来

 运行成功后我们再看下存放字节码文件的目录,可以发现多出来了一个class文件;

 让我们看下使用反编译工具来看下里面会有什么:

 好了!这下真相大白了,在我们运行时,lambda表达式会通过一个最终类去实现并重写了接口中的方法,方法中调用的就是生成出来的一个静态方法,这个静态方法里边放的就是我们的相关处理逻辑,真相浮出水面,但我们还缺少了验证,接下来我们使用debug看下方法栈中是不是真的有lambda$main$0()这个方法被调用了!!!

可以看到在方法栈中确实是调用了这个生成出来的静态方法!!! 

今天就到这里啦~对你有帮助的话不妨留个赞呗!(写这个真的不容易)

 🥇原创不易,还希望各位大佬支持一下!

👍点赞,你的认可是我创作的动力 !

🌟收藏,你的青睐是我努力的方向!

✏️评论,你的意见是我进步的财富!

  • 38
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 44
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 44
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦境游子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值