JDK8辅助学习(一):Lambda表达式原理分析

前言

       本文来了解 Lambda 表达式的实现原理   ------>接上文:JDK8新特性(一):Lambda表达式 。

       通过上文,我们知道 Lambda表达式的出现,就是针对使用匿名内部类语法冗余的问题。所以在分析 Lambda 表达式原理的同时,首先我们先来了解一下 匿名内部类 的实现原理。

1.匿名内部类实现原理

  ①附Demo

/**
 * TODO Swim接口
 *
 * @author liuzebiao
 * @Date 2020-1-2 15:57
 */
public interface ISwim {
    //swimming()抽象方法
    public abstract void swimming();
}
/**
 * TODO 匿名内部类方式原理分析
 *
 * @author liuzebiao
 * @Date 2020-1-3 10:25
 */
public class ResourceAnalysis {

    public static void main(String[] args) {

        goSwimming(new ISwim() {
            @Override
            public void swimming() {
                System.out.println("匿名内部类:goSwimming()方法");
            }
        });
    }

    //定义goSwimming()方法,参数为接口类 ISwim
    public static void goSwimming(ISwim swim){
        swim.swimming();
    }
}

//测试结果:
//    匿名内部类:goSwimming()方法

  ②查看编译后的 .class 文件,然后通过 反编译工具 打开.class 文件

此处我们发现了一点蹊跷,匿名内部类在 ResourceAnalysis.class 的基础上新生成了一个 ResourceAnalysis$1.class 文件

接下来我们使用 反编译工具 XJad 来看一下 ResourceAnalysis$1.class 文件(jd-gui 出来不是这个效果,可能工具原因)

我们发现 ResourceAnalysis$1 类实现了 ISwim接口,并重写了 swimming()方法

2.Lambda表达式实现原理

  ①附Demo

/**
 * TODO Lambda表达式原理分析
 *
 * @author liuzebiao
 * @Date 2020-1-3 10:25
 */
public class ResourceAnalysis {

    public static void main(String[] args) {

        goSwimming(() -> {
            System.out.println("匿名内部类:goSwimming()方法");
        });
    }

    //定义goSwimming()方法,参数为接口类 ISwim
    public static void goSwimming(ISwim swim){
        swim.swimming();
    }
}

  ②查看编译后的 .class 文件,我们发现 Lambda方式并没有生成像匿名内部类方式的 ResourceAnalysis$1.class 文件

  

  ③我们通过 反编译工具 打开.class 文件,发现(XJad)是无法打开的。我们使用 JDK 自带的一个工具:javap 对字节码进行反汇编,查看字节码指令

javap -c -p 文件名.class

-c:表示对代码进行反汇编

-p:显示所有类和成员(包括私有成员)

我们分析对比,发现汇编后的代码,多了一个私有的静态方法 lambda$main$0() 方法

       我们打断点,再次执行,发现它会跳转到一个名为 lambda$main$0()的方法,如下图所示。此时你就知道 lambda$main$0()具体是个什么方法了吧。

       既然了解了 lambda$main$0() 方法,那么这个方法是如何被调用的呢?其实 Lambda在运行的时候会生成一个内部类,为了验证是否生成内部类,我们可以在代码运行时加上 -Djdk.internal.lambda.dumpProxyClasses,加上这个参数后,运行时会将生成的内部类 class 码输出到一个文件中,使用 java 命令如下:

java -Djdk.internal.lambda.dumpProxyClasses 要运行的包名.类名

       在cmd 命令行,编译后的class 路径下,输入以上命令,可以成功执行 ResourceAnalysis 类,如下图所示。

       此时你再次进入编译后的文件中,你会发现运行该命令后,多处一个名为 ResourceAnalysis$$Lambda$1.class 的 class 文件,如下图所示。

      

      我们将 ResourceAnalysis$$Lambda$1.class 反编译,反编译后结果如下图所示。

      

       我们发现也是一个匿名内部类的形式,那么这个匿名内部类到底应该放在哪里执行呢? Lambda表达式源码分析的一系列流程,如下图所示。

  1.  lambda$main$0() 私有静态方法的生成
  2. ResourceAnalysis$$Lambda$1.class 反编译类
  3. 对反编译后的类进行整合。    发现 Lambda表达式,最终的实现还是基于匿名内部类的方式


附:JDK8新特性(目录)

    本目录为 JDK8新特性 学习目录,包含JDK8 新增全部特性的介绍。

    如需了解,请跳转链接查看:我是跳转链接


Lambda表达式原理分析,至此介绍完毕

如果本文对你有所帮助,那就给我点个赞呗 ^_^ 

End

发布了247 篇原创文章 · 获赞 44 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/lzb348110175/article/details/103815744