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

因此,考虑一个接口(interface)示例 I和一类 A具有以下定义:

interface I{ int foo(); } 
class A implements I{  
  public int foo(){return 7;}  
  public static int bar(){return 11;} 
} 

我们可以分配给类型为 I 的变量A 的实例或对方法 bar方法引用A .两者都可以存储在 I 类型的变量上,例如:

I i1 = new A();  
I i2 = A::bar; 

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

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正在存储 A 的一个实例与 I 兼容.但是,由于 i2 = A::bar我们正在存储 8: invokedynamic #4, 0 的结果.

所以,这意味着 invokedynamic 的结果始终是目标类型 的实例,即我们使用方法引用分配的变量类型?

请您参考如下方法:

每个invokedynamic 字节码都引用一个对应的CONSTANT_InvokeDynamic_info常量池中的结构。此结构包含一个 Method Descriptor用于派生此 invokedynamic 指令的参数类型和返回值类型。

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

8: invokedynamic #4,  0              // InvokeDynamic #0:foo:()LI; 
                                                             ^^^^^ 

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


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!