如何存储invokedynamic的结果?

Mig*_*boa 2 jvm invokedynamic java-8

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

因此,考虑一个接口IA具有以下定义的类的示例:

interface I{ int foo(); }
class A implements I{ 
  public int foo(){return 7;} 
  public static int bar(){return 11;}
}
Run Code Online (Sandbox Code Playgroud)

我们可以分配给类型的变量I的实例A方法参考该方法barA.两者都可以存储在类型的变量中I,例如:

I i1 = new A(); 
I i2 = A::bar;
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

因为i1 = new A();这显然是相应的指令7: astore_1存储A与之兼容的实例I.但是,由于i2 = A::bar我们正在存储结果8: invokedynamic #4, 0.

那么,这意味着a的结果invokedynamic总是一个目标类型的实例,它是我们用方法引用分配的变量的类型?

apa*_*gin 6

每个invokedynamic字节码指的是常量池中对应的CONSTANT_InvokeDynamic_info结构.此结构包含一个方法描述符,用于派生参数的类型和该invokedynamic指令的返回值的类型.

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

8: invokedynamic #4,  0              // InvokeDynamic #0:foo:()LI;
                                                             ^^^^^
Run Code Online (Sandbox Code Playgroud)

这意味着此特定字节码不需要参数,并始终生成类型的结果I.