首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何存储invokedynamic的结果?

如何存储invokedynamic的结果?
EN

Stack Overflow用户
提问于 2015-03-24 16:50:43
回答 2查看 170关注 0票数 2

Java 8引入了对一流函数的支持,它允许将函数分配给变量.在这种情况下,变量必须是函数类型的,它由函数接口(只有一个抽象方法的接口)定义。

因此,考虑具有以下定义的接口I和类A的示例:

代码语言:javascript
复制
interface I{ int foo(); }
class A implements I{ 
  public int foo(){return 7;} 
  public static int bar(){return 11;}
}

我们可以将I类型的变量指定为A的实例,也可以将方法引用A的方法bar。这两个变量都可以存储在I类型的变量上,例如:

代码语言:javascript
复制
I i1 = new A(); 
I i2 = A::bar;

如果我们分析前一段代码的编译所产生的字节码,我们将得到:

代码语言:javascript
复制
0: new           #2                  // class A
3: dup
4: invokespecial #3                  // Method A."<init>":()V
7: astore_1
8: invokedynamic #4,  0              // InvokeDynamic #0:foo:()LI;
13: astore_2

对于i1 = new A();,很明显,对应的指令7: astore_1正在存储与I兼容的A实例。但是,作为i2 = A::bar的结果,我们正在存储8: invokedynamic #4, 0的结果。

因此,这意味着invokedynamic的结果总是目标类型的实例,而是我们用方法引用分配的变量的类型?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-03-24 17:53:08

每个invokedynamic字节码都引用常量池中相应的信息结构。此结构包含一个方法描述符,用于派生参数的类型和此invokedynamic指令的返回值类型。

在您的示例中,方法描述符是在源到字节码转换期间计算的()LI;

代码语言:javascript
复制
8: invokedynamic #4,  0              // InvokeDynamic #0:foo:()LI;
                                                             ^^^^^

这意味着这个特定的字节码不需要参数,并且总是产生I类型的结果。

票数 6
EN

Stack Overflow用户

发布于 2015-03-24 17:59:11

invokedynamic指令的结果--Java 8的lambda表达式和方法引用使用它的方式--确实是目标函数interface的一个实例。

这不是JVM记住的invokedynamic指令的结果,而是引导方法返回的CallSite,在新的Java8中,LambdaMetafactory的两种方法之一都具有这种特性。

链接到CallSite指令的invokedynamic实例封装行为,而不是特定的结果值。LambdaMetafactory提供的实际行为是有意不指定的,以提供广泛的自由度,但是当前的实现显示了两种不同的行为。

对于非捕获的lambda表达式,行为是返回在invokedynamic引导过程中创建的单个实例。这可以通过创建包装在MethodHandle中的ConstantCallSite来实现。在这种情况下,invokedynamic指令的后续执行将对此实例进行计算。

对于捕获值的lambda表达式,指令将与接受捕获值的生成类的构造函数或工厂方法相链接。因此,invokedynamic指令的后续执行将表现为一个普通的对象构造(这将创建类的一个新实例,该类每次实现目标interface )。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29238441

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档