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
类型的结果。