モジュール java.base
パッケージ java.lang.invoke

クラスLambdaMetafactory

java.lang.Object
java.lang.invoke.LambdaMetafactory

public final class LambdaMetafactory extends Object

おそらく型適応と引数の部分評価の後に、指定されたMethodHandleへの委譲によって、1つ以上のインタフェースを実装する単純な関数オブジェクトの作成を容易にするメソッド。 これらのメソッドは一般に、invokedynamicコール・サイトのブートストラップ・メソッドとして使用され、Javaプログラミング言語のラムダ式およびメソッド参照式機能をサポートします。

提供されたMethodHandleによって指定された動作への間接アクセスは、3つのフェーズで順番に進行します。

  • リンケージ。このクラスのメソッドが呼び出されたときに発生します。 引数として、実装するインタフェース(通常、「機能インタフェース」は単一の抽象メソッドを持ちます)、実装するインタフェースからのメソッドの名前およびシグネチャ、そのメソッドに必要な実装動作を記述する「ダイレクト・メソッド・ハンドル」、およびその他の追加メタデータ、および適切なファンクション・オブジェクトの作成にターゲットを使用できるCallSiteを生成します。

    リンクには、ターゲット・インタフェースを実装する新しいクラスを動的にロードしたり、適切な既存クラスを再利用したりすることが必要な場合があります。

    CallSiteは関数オブジェクトのファクトリと見なすことができるため、これらのリンケージ・メソッドはメタファクトリと呼ばれます。

  • キャプチャCallSiteのターゲットが呼び出されるときに発生し(一般的にinvokedynamicコール・サイトによって)、関数オブジェクトを生成します。 これは、単一ファクトリCallSiteに対して何度も発生する場合があります。

    動作MethodHandleに、指定されたインタフェース・メソッドのパラメータ以外の追加パラメータがある場合、これらは「取得されたパラメータ」と呼ばれます。これは、CallSiteターゲットの引数として指定する必要があります。 取得されるパラメータの数およびタイプは、リンク時に決定されます。

    取得には、新しい関数オブジェクトの割当てが含まれることも、適切な既存の関数オブジェクトを返す場合もあります。 取得によって生成されたファンクション・オブジェクトのアイデンティティは予測不能であるため、アイデンティティに敏感な操作(参照等価、オブジェクト・ロック、 System.identityHashCode()など)では、異なる実装、または同じ実装での異なる呼出しでさえ異なる結果になる場合があります。

  • 呼出し。実装されたインタフェース・メソッドが関数オブジェクトで呼び出されたときに発生します。 これは、単一関数オブジェクトに対して何度も発生する場合があります。 実装MethodHandleによって参照されるメソッドが呼び出され、取得された引数および呼出し引数に渡されます。 メソッドの結果が返されます。

呼出しで許可される入力または結果のセットを制限することが便利な場合があります。 たとえば、ジェネリック・インタフェースPredicate<T>Predicate<String>としてパラメータ化されるときは、入力はStringである必要があります(実装するメソッドが任意のObjectを許可していても)。 リンク時に、追加のMethodTypeパラメータは"動的"メソッド・タイプを記述します。起動時には、引数および最終結果がこのMethodTypeに対してチェックされます。

このクラスは2つの形式のリンケージ・メソッドを提供します。最適化されたプロトコルを使用する標準版(metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType))と、代替版(altMetafactory(MethodHandles.Lookup, String, MethodType, Object...))です。 代替版は標準版の一般化したもので、フラグおよび追加引数を介して生成された関数オブジェクトの動作に対する追加制御を提供します。 代替版では、関数オブジェクトの次の属性を管理する機能が追加されます。

  • 複数のメソッド。 引数または戻り型の適応を含む、メソッド・シグネチャの複数のバリエーションを実装するのに役立つ場合があります。 これは、メソッドの複数の異なるVMシグネチャが、言語によって論理的に同じメソッドであると見なされるときに発生します。 フラグFLAG_BRIDGESは、追加のMethodTypeのリストが提供されることを示します(それぞれが結果の関数オブジェクトによって実装される)。 これらのメソッドは同じ名前およびインスタンス化された型を共有します。
  • 複数のインタフェース。 必要に応じて、関数オブジェクトは複数のインタフェースを実装できます。 (これらの追加インタフェースは一般的に、メソッドなしのマーカー・インタフェースです。) フラグFLAG_MARKERSは、追加インタフェースのリストが提供されることを示します(それぞれが結果の関数オブジェクトによって実装される)。
  • 直列化可能性。 生成された関数オブジェクトは一般的に直列化をサポートしません。 必要に応じて、関数オブジェクトが直列化可能であるべきことを示すためにFLAG_SERIALIZABLEを使用できます。 直列化可能関数オブジェクトは、キャプチャ・クラス(MethodHandles.Lookupのパラメータcallerによって記述されるクラス)からの追加支援を必要とする、SerializedLambdaクラスのインスタンスを、直列化形式として使用します。詳細は、SerializedLambdaを参照してください。

リンケージ引数は次のことを前提とします。

  • factoryType (CallSiteシグネチャの説明)には、タイプ(D1..Dk)および戻り型RdのKパラメータがあります
  • interfaceMethodType (実装されたメソッド・タイプの説明)には、タイプ(U1..Un)および戻り型RuのNパラメータがあります
  • implementation (実装を提供するMethodHandle)には、タイプ(A1..Am)および戻り型Ra (メソッドがインスタンス・メソッドを記述する場合、このメソッド・ハンドルのメソッド・タイプには、受信側に対応する追加の第1引数がすでに含まれています)のMパラメータがあります
  • dynamicMethodType (起動時の制限の許可)には、タイプ(T1..Tn)および戻り型RTのNパラメータがあります。

さらに、次のリンケージ不変条件を保持する必要があります。

  • interfaceMethodTypedynamicMethodTypeは同じアリティNを持ち、i=1..Nの場合、TiとUiは同じタイプであるか、TiとUiの両方が参照タイプであり、TiはUiのサブタイプです
  • RtおよびRuが同じ型、または両方が参照型かつRtがRuのサブタイプ
  • K + N = M
  • i=1..Kの場合、Di = Ai
  • i=1..Nの場合、TiはAjに適応可能、j=i+k
  • 戻り型Rtがvoid、または戻り型RaがvoidでなくRtに適応可能

また、取得時にimplementationがインスタンス・メソッドに対応し、取得引数(K > 0)がある場合、最初の取得引数(レシーバに対応)はNULL以外である必要があります。

次のように型QはSに適応可能と見なされます。

適応可能型
QSリンク時チェック呼出し時チェック
プリミティブプリミティブ Qはプリミティブ・ワイドニング変換でSに変換可能 なし
プリミティブリファレンス SはWrapper(Q)のスーパータイプ Wrapper(Q)からSにキャスト
リファレンスプリミティブ パラメータ型の場合: Qはプリミティブ・ラッパー、Primitive(Q)はSにワイドニング可能
戻り型の場合: Qがプリミティブ・ラッパーの場合はPrimitive(Q)がSにワイドニング可能かをチェック
Qがプリミティブ・ラッパーでない場合、Qを基底Wrapper(S)にキャスト。たとえば、数値型の場合はNumber
リファレンスリファレンス for parameter types: S is a supertype of Q
for return types:なし
QからSにキャスト

APIのノート:
これらのリンケージ・メソッドはJava言語のラムダ式およびメソッド参照の評価をサポートするように設計されています。 ソース・コード内のすべてのラムダ式またはメソッド参照に、関数型インタフェースであるターゲット型が存在します。 ラムダ式を評価することで、そのターゲット型のオブジェクトが生成されます。 ラムダ式の評価で推奨されるメカニズムは、メソッドのラムダ本文を脱糖し、invokedynamicコール・サイト(静的引数リストが関数型インタフェースの唯一のメソッドおよび脱糖された実装メソッドを記述し、ターゲット型を実装するオブジェクト(ラムダ・オブジェクト)を返す)を呼び出すことです。 (メソッド参照の場合、実装メソッドは単に参照されるメソッドです、脱糖は必要ありません。)

実装メソッドの引数リストとインタフェース・メソッドの引数リストはいくつかの点で異なる場合があります。 実装メソッドは、ラムダ式によってキャプチャされる引数に対応するために追加引数を持つ場合があります。引数に許可された適応(キャスト、ボクシング、アンボクシング、プリミティブ・ワイドニングなど)による違いがある場合もあります。 (可変引数適応はメタファクトリによって扱われません。これらは呼出し元によって扱われることが期待されます。)

invokedynamicコール・サイトには2つの引数リスト、静的引数リストと動的引数リストがあります。 静的引数リストは定数プールに格納されますが、動的引数はキャプチャ時にオペランド・スタックにプッシュされます。 ブートストラップ・メソッドは、静的引数リスト全体(この場合、実装メソッド、ターゲット・インタフェースおよびターゲット・インタフェース・メソッドを記述する情報を含む)、動的引数の数と静的な型(ただし値ではない)およびinvokedynamicサイトの静的な戻り型を記述するメソッド・シグネチャにアクセスできます。

実装メソッドは、メソッドまたはコンストラクタを参照する直接メソッド・ハンドルを使用して記述します。 理論的には、メソッド・ハンドルを使用できますが、これは実装手法と互換性がなく、作業実装が複雑になる場合があります。

導入されたバージョン:
1.8