读过上一篇之后,相信对Lambda表达式的语法以及基本原理有了一定了解。对于编写代码,有这些知识已经够用。本文将进一步区分Lambda表达式和匿名内部类在JVM层面的区别,如果对这一部分不感兴趣,可以跳过

经过第一篇的的介绍,我们看到Lambda表达式似乎只是为了简化匿名内部类书写,这看起来仅仅通过语法糖在编译阶段把所有的Lambda表达式替换成匿名内部类就可以了。但实时并非如此。在JVM层面,Lambda表达式和匿名内部类有着明显的差别。

匿名内部类实现

匿名内部类仍然是一个类,只是不需要程序员显示指定类名,编译器会自动为该类取名。因此如果有如下形式的代码,编译之后将会产生两个class文件:

public class MainAnonymousClass {public static void main(String[] args) {new Thread(new Runnable(){@Overridepublic void run(){System.out.println("Anonymous Class Thread run()");}}).start();;}
}

编译之后文件分布如下,两个class文件分别是主类和匿名内部类产生的:

进一步分析主类MainAnonymousClass.class的字节码,可发现其创建了匿名内部类的对象:

// javap -c MainAnonymousClass.class
public class MainAnonymousClass {...public static void main(java.lang.String[]);Code:0: new           #2                  // class java/lang/Thread3: dup4: new           #3                  // class MainAnonymousClass$1 /*创建内部类对象*/7: dup8: invokespecial #4                  // Method MainAnonymousClass$1."<init>":()V11: invokespecial #5                  // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V14: invokevirtual #6                  // Method java/lang/Thread.start:()V17: return
}

Lambda表达式实现

Lambda表达式通过invokedynamic指令实现,书写Lambda表达式不会产生新的类。如果有如下代码,编译之后只有一个class文件:

public class MainLambda {public static void main(String[] args) {new Thread(() -> System.out.println("Lambda Thread run()")).start();;}
}

编译之后的结果:

通过javap反编译命名,我们更能看出Lambda表达式内部表示的不同:

// javap -c -p MainLambda.class
public class MainLambda {...public static void main(java.lang.String[]);Code:0: new           #2                  // class java/lang/Thread3: dup4: invokedynamic #3,  0              // InvokeDynamic #0:run:()Ljava/lang/Runnable; /*使用invokedynamic指令调用*/9: invokespecial #4                  // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V12: invokevirtual #5                  // Method java/lang/Thread.start:()V15: returnprivate static void lambda$main$0();  /*Lambda表达式被封装成主类的私有方法*/Code:0: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;3: ldc           #7                  // String Lambda Thread run()5: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V8: return
}

反编译之后我们发现Lambda表达式被封装成了主类的一个私有方法,并通过invokedynamic指令进行调用。

推论,this引用的意义

既然Lambda表达式不是内部类的简写,那么Lambda内部的this引用也就跟内部类对象没什么关系了。在Lambda表达式中this的意义跟在表达式外部完全一样。因此下列代码将输出两遍Hello Hoolee,而不是两个引用地址。

public class Hello {Runnable r1 = () -> { System.out.println(this); };Runnable r2 = () -> { System.out.println(toString()); };public static void main(String[] args) {new Hello().r1.run();new Hello().r2.run();}public String toString() { return "Hello Hoolee"; }
}

Lambda 表达式详解~深入JVM实现原理相关推荐

  1. java拉姆达表达式事例,Java Lambda表达式详解和实例

    简介 Lambda表达式是Java SE 8中一个重要的新特性.lambda表达式允许你通过表达式来代替功能接口. lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体( ...

  2. java lambda表达式详解_Java8新特性Lambda表达式详解

    课程目标: 通过本课程的学习,详细掌握Java8新特性之Lambda表达式: 适用人群:有Java基础的开发人员: 课程概述:从Java 8出现以来lambda是最重要的特性之一,它可以让我们用简洁流 ...

  3. Java8 Lambda表达式详解手册及实例

    先贩卖一下焦虑,Java8发于2014年3月18日,距离现在已经快6年了,如果你对Java8的新特性还没有应用,甚至还一无所知,那你真得关注公众号"程序新视界",好好系列的学习一下 ...

  4. Lambda 表达式详解~Stream Pipelines

    前面我们已经学会如何使用Stream API,用起来真的很爽,但简洁的方法下面似乎隐藏着无尽的秘密,如此强大的API是如何实现的呢?比如Pipeline是怎么执行的,每次方法调用都会导致一次迭代吗?自 ...

  5. Lambda 表达式详解~Lambda与集合

    我们先从最熟悉的*Java集合框架(Java Collections Framework, JCF)*开始说起. 为引入Lambda表达式,Java8新增了java.util.funcion包,里面包 ...

  6. java lambda表达式详解_Java8新特性:Lambda表达式详解

    在 Java 版本的历次更新迭代中,Java8 是一个特殊的存在,与以往的版本升级不同.我们对 Java8 似乎抱有更大的期待,因为它是 Java5 之后最重要的一次升级,提供了十多个新特性,其中 L ...

  7. 【C++】Lambda 表达式详解

    语法糖:Lambda 表达式 一.Lambda表达式简介 二.Lambda表达式语法解析 1. Lambda exp 基本语法结构 2. 捕获变量的几种方式 3. mutable关键字 三.Lambd ...

  8. java Lambda表达式详解

    文章目录 一.背景 1.1语法 1.2函数式接口 二.Lambda的基本使用 2.1引子 2.2常见的使用方式 2.3语法小结 三.变量捕获 3.1 匿名内部类 3.2 匿名内部类的变量捕获 3.3L ...

  9. JAVA之Lambda表达式详解

    文章目录 一.基本概念 1.背景 2.Lambda表达式的语法 3.函数式接口 二.Lambda表达式的基本使用 1.无返回值函数式接口 2.有返回值函数接口 3.语法精简 三.变量捕获 1.匿名内部 ...

最新文章

  1. 阿里一面:如何保障消息100%投递成功、消息幂等性?
  2. PowerShell导出共存环境下的Exchange数据库列表
  3. 双击SDK Manager.exe和AVD Manager.exe时,弹出提示:failed to execute tools\android.bat解决办法
  4. 静态成员变量的初始化,vector类型变量初始化
  5. 可以对同一个html元素定义不同的样式,CSS的多种选择器的使用.ppt
  6. python通过ip池爬_python爬虫18 | 就算你被封了也能继续爬,使用IP代理池伪装你的IP地址,让IP飘一会...
  7. 获取python安装路径
  8. 微信小程序 基础操作(边做边学2)
  9. python读取csmar_Python:爬取上市公司公告-Wind-CSMAR
  10. 傅里叶变换及拉普拉斯变换直观理解总结
  11. linux卫星添加,卫星电视卡在linux下的应用
  12. c语言编程入门教程+网易,人话讲编程·C语言入门:第一讲,Hello World
  13. vb里的lbound和ubound的用法
  14. 计算机系统硬件有哪些重要的部件呢?
  15. 【踩坑】RTX30系列显卡的CUDA配置
  16. java并发-ReentrantReadWriteLock读写锁
  17. 域名批量查询 网站域名批量查询
  18. 2022软考高级架构设计师-经历分享
  19. 英酷词典 使用方法 必知必会
  20. 【笔记】2022.5.9 网页数据收集

热门文章

  1. Netty堆外内存泄露排查盛宴
  2. java架构师进阶之独孤九剑:数据结构以及书籍推荐
  3. Python中实现模糊匹配的魔法库:FuzzyWuzzy
  4. 维多利亚的秘密 2005-2018年视频合集
  5. windows下安装Sublime+Miktex+Sumatrapdf配置LATEX环境
  6. Android官方开发文档Training系列课程中文版:Activity测试之测试环境配置
  7. 记录对String.format(Formatter().format())方法的总结
  8. BUAA_OO_第二单元作业总结
  9. 编程开发之--java多线程学习总结(3)类锁
  10. MySQL索引的索引长度问题