モジュール 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
  • フィールド詳細

  • メソッドの詳細

    • metafactory

      public static CallSite metafactory(MethodHandles.Lookup caller, String interfaceMethodName, MethodType factoryType, MethodType interfaceMethodType, MethodHandle implementation, MethodType dynamicMethodType) throws LambdaConversionException
      適切な型適応および引数の部分評価の後、指定されたMethodHandleへの委譲により、1つ以上のインタフェースを実装する単純な関数オブジェクトの作成を容易にします。 一般的にinvokedynamicコール・サイトのブートストラップ・メソッドとして、Javaプログラミング言語のラムダ式およびメソッド参照式機能をサポートするために使用されます。

      これは標準の、合理化されたメタファクトリです。altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)によってより高い柔軟性が提供されます。 このメソッドの動作の概要はすでに説明済です。

      このメソッドから返されたCallSiteのターゲットが呼び出されると、結果として得られる関数オブジェクトは、戻り値のfactoryTypeという名前のインタフェースを実装するクラスのインスタンスであり、interfaceMethodNameおよびinterfaceMethodTypeによって指定される名前のメソッドが宣言されます。 Objectからの追加メソッドをオーバーライドすることもできます。

      パラメータ:
      caller - 呼出し元のアクセス可能性権限を持つルックアップ・コンテキストを表します。 特に、参照コンテキストには「完全な権限アクセス」が必要です。 invokedynamicで使用されるときは、これはVMによって自動的にスタックされます。
      interfaceMethodName - 実装メソッドの名前。 invokedynamicで使用されるときは、これはInvokeDynamic構造のNameAndTypeによって提供され、VMによって自動的にスタックされます。
      factoryType - CallSiteの予想されるシグネチャ。 パラメータ型はキャプチャ変数の型を表し、戻り型は実装するインタフェースです。 invokedynamicで使用されるときは、これはInvokeDynamic構造のNameAndTypeによって提供され、VMによって自動的にスタックされます。
      interfaceMethodType - 関数オブジェクトによって実装されるメソッドのシグネチャおよび戻り型。
      implementation - 起動時に(引数の型と戻り型への適切な適応と、起動引数の前に取得された引数を使用)と呼ばれる実装メソッドを記述する直接メソッド・ハンドル。
      dynamicMethodType - 起動時に動的に適用するシグネチャと戻り型。 単純なユースケースでは、これはinterfaceMethodTypeと同じです。
      戻り値:
      ターゲットを使用して取得を実行し、factoryTypeという名前のインタフェースのインスタンスを生成できるCallSite
      例外:
      LambdaConversionException - callerに完全な権限アクセス権がない場合、またはinterfaceMethodNameが有効なJVMメソッド名でない場合、またはfactoryTypeの戻りタイプがインタフェースでない場合、またはimplementationがメソッドまたはコンストラクタを参照する直接メソッド・ハンドルでない場合、または定義済のaboveのようにリンク不変者に違反している場合。
      NullPointerException - 引数がnullの場合。
      SecurityException - セキュリティ・マネージャが存在し、「アクセスを拒否」callerからimplementationのパッケージである場合。
    • altMetafactory

      public static CallSite altMetafactory(MethodHandles.Lookup caller, String interfaceMethodName, MethodType factoryType, Object... args) throws LambdaConversionException
      適切な型適応および引数の部分評価の後、指定されたMethodHandleへの委譲により、1つ以上のインタフェースを実装する単純な関数オブジェクトの作成を容易にします。 一般的にinvokedynamicコール・サイトのブートストラップ・メソッドとして、Javaプログラミング言語のラムダ式およびメソッド参照式機能をサポートするために使用されます。

      これは一般的で、柔軟性の高いメタファクトリです。合理化されたバージョンがmetafactory(java.lang.invoke.MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)によって提供されます。 このメソッドの動作の概要はすでに説明済です。

      このメソッドの引数リストには3つの固定パラメータが含まれ、invokedynamic呼出しでブートストラップ・メソッドのためにVMによって自動的にスタックされるパラメータと、追加パラメータを含むObject[]パラメータに対応しています。 このメソッドに宣言される引数リストは次のとおりです。

      
        CallSite altMetafactory(MethodHandles.Lookup caller,
                                String interfaceMethodName,
                                MethodType factoryType,
                                Object... args)
       

      しかし、引数リストが以下であるかのように動作します。

      
        CallSite altMetafactory(MethodHandles.Lookup caller,
                                String interfaceMethodName,
                                MethodType factoryType,
                                MethodType interfaceMethodType,
                                MethodHandle implementation,
                                MethodType dynamicMethodType,
                                int flags,
                                int altInterfaceCount,        // IF flags has MARKERS set
                                Class... altInterfaces,       // IF flags has MARKERS set
                                int altMethodCount,           // IF flags has BRIDGES set
                                MethodType... altMethods      // IF flags has BRIDGES set
                                )
       

      metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)の引数リスト内の引数は、そのメソッド内と同じ仕様を持ちます。 追加引数は次のように解釈されます。

      • flagsは追加オプションを示します。これは、必要なフラグのビット単位ORです。 定義済フラグはFLAG_BRIDGESFLAG_MARKERSおよびFLAG_SERIALIZABLEです。
      • altInterfaceCountは、ファンクション・オブジェクトが実装する必要のある追加インタフェースの数で、FLAG_MARKERSフラグが設定されている場合にのみ存在します。
      • altInterfacesは、実装する追加インタフェースの可変長リストで、長さはaltInterfaceCountで、FLAG_MARKERSフラグが設定されている場合にのみ存在します。
      • altMethodCountは、ファンクション・オブジェクトが実装する必要がある追加のメソッド・シグネチャの数で、FLAG_BRIDGESフラグが設定されている場合にのみ存在します。
      • altMethodsは、実装する追加メソッド・シグネチャの可変長リストで、長さはaltMethodCountであり、FLAG_BRIDGESフラグが設定されている場合にのみ存在します。

      altInterfacesで指定された各クラスは、aboveで説明されているように、Rd (factoryTypeの戻り型)と同じ制限に従います。 altMethodsで指定された各MethodTypeは、aboveで説明されているように、interfaceMethodTypeと同じ制限に従います。

      flagsにFLAG_SERIALIZABLEが設定されているとき、関数オブジェクトはSerializableを実装し、適切なSerializedLambdaを返すwriteReplaceメソッドを持ちます。 callerクラスは、SerializedLambdaで説明したとおり適切な$deserializeLambda$メソッドを持つ必要があります。

      このメソッドから返されるCallSiteのターゲットが呼び出されるとき、結果の関数オブジェクトは次のプロパティを持つクラスのインスタンスです。

      • クラスは、factoryTypeの戻り型およびaltInterfacesによって命名されたインタフェースを実装
      • クラスは、interfaceMethodNameで指定された名前と、interfaceMethodTypeによって与えられたシグネチャ、およびaltMethodsによって指定される追加のシグネチャを含むメソッドを宣言
      • このクラスはObjectからのメソッドをオーバーライドでき、直列化に関連するメソッドを実装できます。

      パラメータ:
      caller - 呼出し元のアクセス可能性権限を持つルックアップ・コンテキストを表します。 特に、参照コンテキストには「完全な権限アクセス」が必要です。 invokedynamicで使用されるときは、これはVMによって自動的にスタックされます。
      interfaceMethodName - 実装メソッドの名前。 invokedynamicで使用されるときは、これはInvokeDynamic構造のNameAndTypeによって提供され、VMによって自動的にスタックされます。
      factoryType - CallSiteの予想されるシグネチャ。 パラメータ型はキャプチャ変数の型を表し、戻り型は実装するインタフェースです。 invokedynamicで使用されるときは、これはInvokeDynamic構造のNameAndTypeによって提供され、VMによって自動的にスタックされます。
      args - 前述のとおり、必要な引数interfaceMethodType, implementation, dynamicMethodType, flagsおよび任意のオプションの引数を含むObjectの配列
      戻り値:
      ターゲットを使用して取得を実行し、factoryTypeという名前のインタフェースのインスタンスを生成できるCallSite
      例外:
      LambdaConversionException - callerに完全な権限アクセス権がない場合、またはinterfaceMethodNameが有効なJVMメソッド名でない場合、またはfactoryTypeの戻りタイプがインタフェースでない場合、またはaltInterfacesのいずれかがインタフェースでない場合、またはimplementationがメソッドまたはコンストラクタを参照する直接メソッド・ハンドルでない場合、またはaboveの定義に従ってリンク不変者に違反している場合。
      NullPointerException - いずれかの引数またはargsのコンポーネントがnullの場合。
      IllegalArgumentException - argsのコンポーネントの数またはタイプが前述のルールに従っていない場合、またはaltInterfaceCountまたはaltMethodCountが負の整数である場合。
      SecurityException - セキュリティ・マネージャが存在し、「アクセスを拒否」callerからimplementationのパッケージである場合。