代码之家  ›  专栏  ›  技术社区  ›  Miguel Gamboa

如何存储invokedynamic的结果?

  •  2
  • Miguel Gamboa  · 技术社区  · 9 年前

    Java8引入了对一级函数的支持,允许将函数分配给变量。在这种情况下,变量必须是 函数类型 ,由 功能接口 (只有一个抽象方法的接口)。

    因此,考虑一个接口示例 I 还有一节课 A 定义如下:

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

    我们可以赋值给类型为 的实例 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
    

    对于 i1 = new A(); 很明显,相应的指令 7: astore_1 正在存储的实例 A. 。但是,由于 i2 = A::bar 我们正在存储 8: invokedynamic #4, 0 .

    因此,这意味着 invokedynamic 始终是 目标类型 ,哪种类型的变量是我们用方法引用赋值的?

    2 回复  |  直到 9 年前
        1
  •  6
  •   apangin    9 年前

    每个 invokedynamic 字节码是指对应的 CONSTANT_InvokeDynamic_info 恒定池中的结构。此结构包含 Method Descriptor 用于派生参数的类型和此的返回值的类型 调用动态 指示

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

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

    这意味着这个特定的字节码不需要任何参数,并且总是生成类型为 I .

        2
  •  4
  •   Holger    9 年前

    结果 invokedynamic 指令,即Java8s lambda表达式和方法引用使用它的方式,实际上是目标函数的一个实例 interface .

    这不是 调用动态 JVM记住的指令,但 CallSite 如果新的Java8具有 LambdaMetafactory .

    这个 呼叫站点 链接到的实例 调用动态 指令封装 行为 ,而不是特定的结果值。提供的实际行为 Lambda金属工厂 故意未指定以提供广泛的自由度,但当前实现呈现出两种不同的行为。

    对于非捕获lambda表达式,行为将是返回在 调用动态 引导。这可以通过创建 constant wrapping MethodHandle 包裹在 ConstantCallSite 在这种情况下 调用动态 指令将对此实例求值。

    对于捕获值的lambda表达式,指令将链接到接受捕获值的生成类的构造函数或工厂方法。然后 调用动态 指令的行为类似于普通对象构造(它创建实现目标的类的新实例 界面 每次)。

    推荐文章