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 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
对于
I
来说,显然是相应的指令i1 = new A();
正在存储与7: astore_1
兼容的A
实例。但是,作为I
的结果,我们将存储i2 = A::bar
的结果。因此,这意味着
8: invokedynamic #4, 0
的结果始终是目标类型的实例,这是我们通过方法引用分配的变量的类型? 最佳答案
每个invokedynamic
字节码都引用常量池中的对应CONSTANT_InvokeDynamic_info结构。该结构包含一个Method Descriptor,它用于派生此invokedynamic
指令的参数类型和返回值的类型。
在您的示例中,方法描述符是()LI;
在源代码到字节码的转换过程中计算的。
8: invokedynamic #4, 0 // InvokeDynamic #0:foo:()LI;
^^^^^
这意味着该特定字节码不包含任何参数,并且始终产生
I
类型的结果。