当前位置: 首页 > 知识库问答 >
问题:

Java8 lambda编译为内部类、方法还是其他什么?[复制]

戈正初
2023-03-14

我今天读了这篇关于lambdas的文章:

http://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood

本文建议,lambda不是作为一个非内部类实现的(由于性能原因)。它给出了一个示例,可以将lambda表达式编译为类的(静态)方法。

我尝试了一个非常简单的片段:

private void run() {
    System.out.println(this);
    giveHello(System.out::println);
}

private void giveHello(Consumer<String> consumer) {
    System.out.println(consumer);
    consumer.accept("hello");
}

输出是:

sample.Main@14ae5a5
sample.Main$$Lambda$1/168423058@4a574795
hello

所以这不是同一个实例。它也不是一些中央的“Lambda Factory”实例...

那么lambda是如何实现的呢?

共有3个答案

艾宏远
2023-03-14

Java 8中的Lambda是所谓的函数接口,即具有一个默认方法的匿名接口。

莘光华
2023-03-14

我问了自己同样的问题,找到了这个视频,Brian Goetz的演讲。这是对lambdas如何在java中实现的非常有用的介绍。

编辑(摘要):看了一会儿,所以这可能不完全正确。编译文件时,编译器会留下lambda应该做什么的描述。然后,在运行代码时,JRE将决定如何实现lambda。有几个选项,内联,方法引用,匿名类。然后,它将使用动态分配来分配实现。

楚勇
2023-03-14

假设您传递的是实际的lambda表达式而不是方法引用,表达式本身被编译为一个单独的合成方法。除了预期函数接口的任何形式参数(例如,在消费者的情况下是单个String

在lambda表达式或方法引用出现的代码位置,会发出invokedynamic指令。第一次命中此指令时,调用LambdaMetafactory上的引导方法。这个引导方法将修复委托给目标方法的目标函数接口的实际实现,这就是返回的结果。目标方法要么是表示lambda体的合成方法,要么是使用运算符提供的命名方法。在创建实现功能接口的类时,进程被延迟;它不会在编译时发生。

最后,运行时使用引导结果修补invokedynamic站点,引导结果实际上是使用传入的任何捕获值对生成的委托进行构造函数调用,包括(可能)调用目标。这通过删除后续调用的引导过程来减轻性能影响。

参见java。朗。引用“链接时间”一章的末尾,由@Holger提供。

在没有捕获的lambda的情况下,invokedynamic指令通常会解析为一个共享委托实例,该实例可以在后续调用中重用,尽管这是一个实现细节。

 类似资料:
  • 问题内容: 该文章建议,lambda 不能实现为匿名内部类(由于性能)。它给出了一个示例,可以将lambda表达式编译为类的(静态)方法。 我尝试了一个非常简单的代码段: 输出为: 因此,它不是同一实例。这也不是中央“ Lambda Factory”实例。 那么如何实现lambda? 问题答案: 假设您传递的是 实际的lambda表达式 而不是方法引用,则表达式本身将被编译为单独的合成方法。除了预

  • 奇怪的是,标记为“OK”的行编译得很好,但标记为“Error”的行失败了。它们看起来基本上是一样的。

  • 问题内容: 我正在尝试捕获WebBrowser控件的内容。可以完美地工作,但是WebBrowser控件的文档中不支持它。我一直在尝试寻找另一种捕获WebBrowser控件的内容并将其保存到本地图像文件的方法。 是否有人有任何变通办法或其他方法将WebBrowser控件的内容保存到本地图像文件? 问题答案: Control.DrawToBitmap并不总是能正常工作,因此我诉诸于以下提供更一致结果的

  • 问题内容: 现在,这是另一种情况: 这样可以编译并运行… 好的,在最后一个问题中,使用了来自 类的 静态方法。 但是现在不同了:是的字段,是;在这种情况下,它也是a ,并且a 具有碰巧匹配a的签名的方法,而a 是期望的方法 。 所以我尝试了这个 而且有效! 这是一个完全不同的范围,因为我启动了一个新实例,并且可以在构造该实例之后立即使用方法引用! 那么,方法引用真的是 任何 遵循签名的方法吗?有什

  • 问题内容: 就在今天,我需要一种在不同对象之间传递函数的方法。我很快了解到您不能直接在Java中做到这一点,但是您可以传递一个wht实例,该实例显然被称为“匿名内部类”,如下所示: 定义类: 使其成为一个实例: 并称之为: 很简单。但是我不明白的是为什么它被称为“匿名”。我不只是给它起名字MyCallback吗?命名的东西不能匿名,对吗?请避免对这个术语感到困惑。 问题答案: 不,您说的是MyCa

  • 问题内容: 这是我几天前回答的一个后续问题。 编辑: 该问题的OP似乎已经使用了我发布给他的代码来问同样的问题,但是我没有意识到。道歉。提供的答案是不同的! 我基本上观察到: …或者换句话说:无论是否触发条件,拥有该子句都会更快。 我认为这与两者生成的不同字节码有关,但是有人能详细确认/解释吗? 编辑: 似乎不是每个人都可以重现我的时间安排,所以我认为在我的系统上提供一些信息可能有用。我正在运行默