Jvm 如何存储InvokedDynamic的结果?
Java8引入了对一级函数的支持,允许将函数分配给变量。在这种情况下,变量必须为函数类型,由函数接口定义(仅具有一个抽象方法的接口) 因此,考虑具有以下定义的接口Jvm 如何存储InvokedDynamic的结果?,jvm,java-8,invokedynamic,Jvm,Java 8,Invokedynamic,Java8引入了对一级函数的支持,允许将函数分配给变量。在这种情况下,变量必须为函数类型,由函数接口定义(仅具有一个抽象方法的接口) 因此,考虑具有以下定义的接口I和类a的示例: interface I{ int foo(); } class A implements I{ public int foo(){return 7;} public static int bar(){return 11;} } 我们可以为I类型的变量分配a的一个实例,或者为a的方法bar分配方法引用。两者
I
和类a
的示例:
interface I{ int foo(); }
class A implements I{
public int foo(){return 7;}
public static int bar(){return 11;}
}
我们可以为I
类型的变量分配a
的一个实例,或者为a
的方法bar
分配方法引用。两者都可以存储在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
0:new#2//A类
3:dup
4:调用特殊的#3//方法A.“”:()V
7:astore_1
8:invokedynamic#4,0//invokedynamic#0:foo:()LI;
13:astore_2
对于i1=newa()
这显然是相应的指令7:astore_1
正在存储与I
兼容的A
的实例。但是,作为i2=a::bar
的结果,我们正在存储8:invokedynamic#4,0
的结果
因此,这意味着
invokedynamic
的结果始终是目标类型的一个实例,这是我们用方法引用分配的变量类型?每个invokedynamic
字节码引用常量池中的相应结构。此结构包含用于派生此invokedynamic
指令的参数类型和返回值类型的
在您的示例中,方法描述符是()LI代码>在源代码到字节码转换期间计算
8: invokedynamic #4, 0 // InvokeDynamic #0:foo:()LI;
^^^^^
这意味着这个特定字节码不需要参数,并且总是产生类型为I
的结果invokedynamic
指令的结果,Java 8的lambda表达式和方法引用使用它的方式,实际上是目标函数接口的一个实例
JVM记住的不是invokedynamic
指令的结果,而是由bootstrap方法返回的CallSite
,如果是新的Java 8,则使用
链接到invokedynamic
指令的CallSite
实例封装了行为,而不是特定的结果值。LambdaMetafactory
提供的实际行为是故意未指定的,以提供广泛的自由度,但是当前的实现展示了两种不同的行为
对于非捕获lambda表达式,行为将是返回在invokedynamic
引导过程中创建的单个实例。这可以通过创建包装在中的。在这种情况下,invokedynamic
指令的后续执行将计算到此实例
对于捕获值的lambda表达式,将针对接受捕获值的生成类的构造函数或工厂方法链接指令。因此,invokedynamic
指令的后续执行行为将类似于普通对象构造(每次都会创建实现目标接口的类的新实例)