gpt4 book ai didi

java - 为什么使用 invokedynamic 调用 Java 8 lambda?

转载 作者:太空宇宙 更新时间:2023-11-04 11:54:45 24 4
gpt4 key购买 nike

invokedynamic 指令用于帮助虚拟机在运行时确定方法引用,而不是在编译时对其进行硬连接。

这对于动态语言很有用,在动态语言中,直到运行时才知道确切的方法和参数类型。但 Java lambda 的情况并非如此。它们被转换为具有明确定义的参数的静态方法。并且可以使用 invokestatic 调用此方法。

那么 lambda 需要 invokedynamic 吗,尤其是在性能受到影响的情况下?

最佳答案

Lambda 不是使用 invokedynamic 调用的,它们的对象表示是使用 invokedynamic 创建的,实际调用是常规 invokevirtualinvokeinterface

例如:

// creates an instance of (a subclass of) Consumer 
// with invokedynamic to java.lang.invoke.LambdaMetafactory
something(x -> System.out.println(x));

void something(Consumer<String> consumer) {
// invokeinterface
consumer.accept("hello");
}

任何 lambda 都必须成为某个基类或接口(interface)的实例。该实例有时包含从原始方法捕获的变量的副本,有时包含指向父对象的指针。这可以作为匿名类实现。

为什么调用动态

简短的答案是:在运行时生成代码。

Java 维护者选择在运行时生成实现类。这是通过调用 java.lang.invoke.LambdaMetafactory.metafactory 来完成的。由于该调用的参数(返回类型、接口(interface)和捕获的参数)可能会更改,因此需要 invokedynamic

使用invokedynamic在运行时构造匿名类,允许JVM在运行时生成该类字节码。对同一语句的后续调用使用缓存版本。使用 invokedynamic 的另一个原因是能够在将来更改实现策略,而不必更改已编译的代码。

未走的路

另一个选择是编译器为每个 lambda 实例化创建一个内部类,相当于将上述代码翻译为:

something(new Consumer() { 
public void accept(x) {
// call to a generated method in the base class
ImplementingClass.this.lambda$1(x);

// or repeating the code (awful as it would require generating accesors):
System.out.println(x);
}
);

这需要在编译时创建类,然后在运行时加载。 jvm 的工作方式是,这些类将驻留在与原始类相同的目录中。第一次执行使用该 lambda 的语句时,必须加载并初始化该匿名类。

关于性能

第一次调用invokedynamic将触发匿名类生成。然后操作码 invokedynamic 被替换为 code这在性能上相当于手动编写匿名实例化。

关于java - 为什么使用 invokedynamic 调用 Java 8 lambda?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41470740/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com