2

Java 8 では、第一級関数のサポートが導入され、関数を変数に割り当てることができます。この場合、変数は関数型である必要があり、関数型インターフェイス(抽象メソッドが 1 つだけのインターフェイス)によって定義されます。

したがって、次の定義を持つインターフェイスIとクラスの例を考えてみましょう。A

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

型の変数にIのインスタンスAまたは のメソッドへのメソッド参照barを割り当てることができますAI両方とも、次のようなtype の変数に格納できます。

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のある のインスタンスを格納していることは明らかです。しかし、 の結果として、 の結果を保存しています。AIi2 = A::bar8: invokedynamic #4, 0

つまり、 an の結果invokedynamicは常に、メソッド参照で割り当てる変数の型である対象の型のインスタンスになるということです。

4

2 に答える 2

6

invokedynamicバイトコードは、定数プール内の対応するCONSTANT_InvokeDynamic_info構造を参照します。この構造体には、この命令の引数の型と戻り値の型を導出するために使用されるメソッド記述子が含まれています。invokedynamic

あなたの例では、メソッド記述子は()LI;ソースからバイトコードへの変換中に計算されます。

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

これは、この特定のバイトコードが引数を期待せず、常に type の結果を生成することを意味しますI

于 2015-03-24T17:53:08.897 に答える
4

命令の結果、invokedynamicJava 8 のラムダ式とメソッド参照がそれを使用する方法は、実際にはターゲットの Functional のインスタンスですinterface

invokedynamicJVM によって記憶される命令の結果ではなく、CallSiteブートストラップ メソッドによって返されるのは、新しい Java 8 機能の 2 つのメソッドのいずれかの場合ですLambdaMetafactory

CallSite命令にリンクされたインスタンスは、特定の結果値ではなく、動作invokedynamicをカプセル化します。によって提供される実際の動作は、広い自由度を提供するために意図的に指定されていませんが、現在の実装では 2 つの異なる動作が示されています。LambdaMetafactory

非キャプチャ ラムダ式の場合、動作は、invokedynamicブートストラップ中に作成された単一のインスタンスを返すことです。これは、 でラップされた定数ラッピングMethodHandleを作成することで実行できますConstantCallSite。この場合、invokedynamic命令の後続の実行はこのインスタンスに評価されます。

値をキャプチャするラムダ式の場合、命令は、キャプチャされた値を受け入れる生成されたクラスのコンストラクターまたはファクトリ メソッドに対してリンクされます。したがって、invokedynamic命令の後続の実行は、通常のオブジェクト構築のように動作します (interface毎回ターゲットを実装するクラスの新しいインスタンスを作成します)。

于 2015-03-24T17:59:11.970 に答える