我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java怎么看Lambda源码

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java怎么看Lambda源码

本文小编为大家详细介绍“Java怎么看Lambda源码”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java怎么看Lambda源码”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

Java怎么看Lambda源码

1、Demo

首先我们来看一个 Lambda 表达式的 Demo,如下图:

Java怎么看Lambda源码

代码比较简单,就是新起一个线程打印一句话,但对于图中 () -> System.out.println ( “ lambda is run “ ) 这种代码,估计很多同学都感觉到很困惑,Java 是怎么识别这种代码的?

如果我们修改成匿名内部类的写法,就很清楚,大家都能看懂,如下图:

Java怎么看Lambda源码

那是不是说 () -> System.out.println ( “ lambda is run “ ) 这种形式的代码,其实就是建立了内部类呢?其实这就是最简单 Lambda 表达式,我们是无法通过 IDEA 看到源码和其底层结构的,下面我们就来介绍几种可看到其底层实现的方式。

2、异常判断法

我们可以在代码执行中主动抛出异常,打印出堆栈,堆栈会说明其运行轨迹,一般这种方法简单高效,基本上可以看到很多情况下的隐藏代码,我们来试一下,如下图:

Java怎么看Lambda源码

从异常的堆栈中,我们可以看到 JVM 自动给当前类建立了内部类(错误堆栈中出现多次的 $ 表示有内部类),内部类的代码在执行过程中,抛出了异常,但这里显示的代码是 Unknown Source,所以我们也无法 debug 进去,一般情况下,异常都能暴露出代码执行的路径,我们可以打好断点后再次运行,但对于 Lambda 表达式而言,通过异常判断法我们只清楚有内部类,但无法看到内部类中的源码。

3、javap 命令法

javap 是 Java 自带的可以查看 class 字节码文件的工具,安装过 Java 基础环境的电脑都可以直接执行 javap 命令,如下图:

Java怎么看Lambda源码

命令选项中,我们主要是用-v -verbose 这个命令,可以完整输出字节码文件的内容。

接下来我们使用 javap 命令查看下 Lambda.class 文件,在讲解的过程中,我们会带上一些关于 class 文件的知识。

我们在命令窗口中找到 Lambda.class 所在的位置,执行命令:javap -verbose Lambda.class,然后你会看到一长串的东西,这些叫做汇编指令,接下来我们来一一讲解下( 所有的参考资料来自 Java 虚拟机规范,不再一一引用说明):

汇编指令中我们很容易找到 Constant pool 打头的一长串类型,我们叫做常量池,官方英文叫做 Run-Time Constant Pool,我们简单理解成一个装满常量的 table ,table 中包含编译时明确的数字和文字,类、方法和字段的类型信息等等。table 中的每个元素叫做 cpinfo,cpinfo 由唯一标识 ( tag ) + 名称组成,目前 tag 的类型一共有:

Java怎么看Lambda源码

贴出我们解析出来的部分图:

Java怎么看Lambda源码

  1. 图中 Constant pool 字样代表当前信息是常量池;

  2. 每行都是一个 cp_info ,第一列的 #1 代表是在常量池下标为 1 的位置 ;

  3. 每行的第二列,是 cp_info 的唯一标识 ( tag ) ,比如 Methodref 对应着上表中的 CONSTANT_Methodref(上上图中表格中 value 对应 10 的 tag),代表当前行是表示方法的描述信息的,比如说方法的名称,入参类型,出参数类型等,具体的含义在 Java 虚拟机规范中都可以查询到,Methodref 的截图如下:
    Java怎么看Lambda源码

  4. 每行的第三列,如果是具体的值的话,直接显示具体的值,如果是复杂的值的话,会显示 cp_info 的引用,比如说图中标红 2 处,引用两个 13 和 14 位置的 cp_info,13 表示方法名字是 init,14 表示方法无返回值,结合起来表示方法的名称和返回类型,就是一个无参构造器;

  5. 每行的第四列,就是具体的值了。

对于比较重要的 cp_info 类型我们说明下其含义:

  1. InvokeDynamic 表示动态的调用方法,后面我们会详细说明;

  2. Fieldref 表示字段的描述信息,如字段的名称、类型;

  3. NameAndType 是对字段和方法类型的描述;

  4. MethodHandle 方法句柄,动态调用方法的统称,在编译时我们不知道具体是那个方法,但运行时肯定会知道调用的是那个方法;

  5. MethodType 动态方法类型,只有在动态运行时才会知道其方法类型是什么。

我们从上上图中标红的 3 处,发现 Ljava/lang/invoke/MethodHandles$Lookup,java/lang/invoke/LambdaMetafactory.metafactory 类似这样的代码,MethodHandles 和 LambdaMetafactory 都是 java.lang.invoke 包下面的重要方法,invoke 包主要实现了动态语言的功能,我们知道 java 语言属于静态编译语言,在编译的时候,类、方法、字段等等的类型都已经确定了,而 invoke 实现的是一种动态语言,也就是说编译的时候并不知道类、方法、字段是什么类型,只有到运行的时候才知道。

比如这行代码:Runnable runnable = () -> System.out.println(“lambda is run”); 在编译器编译的时候 () 这个括号编译器并不知道是干什么的,只有在运行的时候,才会知道原来这代表着的是 Runnable.run() 方法。invoke 包里面很多类,都是为了代表这些 () 的,我们称作为方法句柄( MethodHandler ),在编译的时候,编译器只知道这里是个方法句柄,并不知道实际上执行什么方法,只有在执行的时候才知道,那么问题来了,JVM 执行的时候,是如何知道 () 这个方法句柄,实际上是执行 Runnable.run() 方法的呢?

首先我们看下 simple 方法的汇编指令:

Java怎么看Lambda源码

从上图中就可以看出 simple 方法中的 () -> System.out.println(“lambda is run”) 代码中的 (),实际上就是 Runnable.run 方法。

我们追溯到 # 2 常量池,也就是上上图中标红 1 处,InvokeDynamic 表示这里是个动态调用,调用的是两个常量池的 cp_info,位置是 #0:#37 ,我们往下找 #37 代表着是 // run:()Ljava/lang/Runnable,这里表明了在 JVM 真正执行的时候,需要动态调用 Runnable.run() 方法,从汇编指令上我们可以看出 () 实际上就是 Runnable.run(),下面我们 debug 来证明一下。

我们在上上图中 3 处发现了 LambdaMetafactory.metafactory 的字样,通过查询官方文档,得知该方法正是执行时, 链接到真正代码的关键,于是我们在 metafactory 方法中打个断点 debug 一下,如下图:

Java怎么看Lambda源码

metafactory 方法入参 caller 代表实际发生动态调用的位置,invokedName 表示调用方法名称,invokedType 表示调用的多个入参和出参,samMethodType 表示具体的实现者的参数,implMethod 表示实际上的实现者,instantiatedMethodType 等同于 implMethod。

以上内容总结一下:

从汇编指令的 simple 方法中,我们可以看到会执行 Runnable.run 方法;

在实际的运行时,JVM 碰到 simple 方法的 invokedynamic 指令,会动态调用 LambdaMetafactory.metafactory 方法,执行具体的 Runnable.run 方法。

所以可以把 Lambda 表达值的具体执行归功于 invokedynamic JVM 指令,正是因为这个指令,才可以做到虽然编译时不知道要干啥,但动态运行时却能找到具体要执行的代码。

接着我们看一下在汇编指令输出的最后,我们发现了异常判断法中发现的内部类,如下图:

Java怎么看Lambda源码

上图中箭头很多,一层一层的表达清楚了当前内部类的所有信息。

读到这里,这篇“Java怎么看Lambda源码”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java怎么看Lambda源码

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java怎么看Lambda源码

本文小编为大家详细介绍“Java怎么看Lambda源码”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java怎么看Lambda源码”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1、Demo首先我们来看一个 La
2023-06-30

java怎么查看注解源码

要查看Java注解的源码,可以按照以下步骤进行:打开Java IDE(例如Eclipse、IntelliJ IDEA)。在项目中找到包含注解的类。将光标放在注解上,然后按住Ctrl键并单击注解。这将打开注解的定义源码文件,允许你查看和
2023-10-26

Java Lambda 表达式源码解析

Java Lambda 源码分析问题:Lambda 表达式是什么?JVM 内部究竟是如何实现 Lambda 表达式的?为什么要这样实现?一、基本概念1、Lambda 表达式下面的例子中,() -> System.out.println("1") 就是一个 La
2021-12-25

java中mongodb源码配置文件怎么查看

查看MongoDB源码配置文件JavaMongoDB驱动器提供便捷方法查看源码配置文件。通过导入驱动器并调用getDefaultOptions(),可获取MongoClientOptions对象。使用get()方法指定ClientOptionName枚举获取配置选项,再以toString()解析显示配置内容。
java中mongodb源码配置文件怎么查看
2024-04-13

如何查看java源代码

要查看Java源代码,可以使用以下几种方法:使用IDE(集成开发环境):常见的Java IDE(Integrated Development Environment,集成开发环境)如Eclipse、IntelliJ IDEA和NetBean
如何查看java源代码
2024-02-29

怎么读Java源码

这篇文章主要讲解了“怎么读Java源码”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么读Java源码”吧!1、建议从JDK源码开始读起,这个直接和eclipse集成,不需要任何配置。可以从
2023-06-17

idea怎么查看注解源码

您可以使用下列步骤来查看idea中注解的源码:首先,在您的项目中找到包含注解的类或方法。将光标放置在注解上,并按下Ctrl键(在Windows和Linux上)或Command键(在Mac上)。单击注解上的链接,这将打开该注解的定义位置。
2023-10-26

怎么查看运行中Java Class源码的三板斧

这篇文章主要讲解了“怎么查看运行中Java Class源码的三板斧”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么查看运行中Java Class源码的三板斧”吧!线上跑了个应用,总感觉运行
2023-06-15

怎么阅读Java源码

本篇内容主要讲解“怎么阅读Java源码”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么阅读Java源码”吧!Java源码初接触如果你进行过一年左右的开发,喜欢用eclipse的debug功能。
2023-06-17

plsql怎么查看数据表源码

在PL/SQL中,无法直接查看数据表的源码。数据表的源码是由数据库管理系统内部维护和管理的,用户无法直接访问和查看。如果你想查看数据表的结构和定义,可以使用以下方法:使用SQL查询:可以使用DESC命令或SELECT * FROM USE
plsql怎么查看数据表源码
2024-02-29

plsql怎么查看sql源码语句

在PL/SQL中,您可以使用以下方法来查看SQL源码语句:1. 使用DBMS_OUTPUT.PUT_LINE函数:您可以在PL/SQL块中使用DBMS_OUTPUT.PUT_LINE函数将SQL语句打印到输出中。例如:```plsqlDEC
2023-10-11

怎么样阅读Java源码

这篇文章主要介绍了怎么样阅读Java源码,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。阅读Java源码的前提条件:1、技术基础在阅读源码之前,我们要有一定程度的技术基础的支持
2023-06-02

idea中如何查看底层Java源码

要查看Java源码,可以使用以下几种方法:使用IDE:主流的Java集成开发环境(IDE)如Eclipse、IntelliJ IDEA等都提供了查看Java源码的功能。在IDE中,可以通过选中要查看的类或方法,然后使用快捷键(例如在Ecli
idea中如何查看底层Java源码
2024-02-29

如何在IDE中查看java源代码

本文以eclipse编辑器为例。1、首先依次点击windows->preference->java->install JARs->选中你的jre->点击Duplicate2、找到 rt.jar并展开,这时会看到Soruce attachement:(none)
如何在IDE中查看java源代码
2020-10-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录