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

クラスLambdaMetafactory



  • public final class LambdaMetafactory
    extends Object

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

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

    • リンケージ。このクラスのメソッドが呼び出されたときに発生します。 これらは引数として、実装されるインタフェース(一般的に関数型インタフェース、単一抽象メソッドを持つもの)、実装されるそのインタフェースからのメソッドの名前とシグネチャ、そのメソッドに求められる実装動作を記述するメソッド・ハンドルを取り(他の追加メタデータを取ることもある)、ターゲットを適切な関数オブジェクトを作成するために使用できるCallSiteを生成します。 リンケージでは、ターゲット・インタフェースを実装する新しいクラスが動的にロードされることもあります。 CallSiteは関数オブジェクトのファクトリと見なすことができるため、これらのリンケージ・メソッドはメタファクトリと呼ばれます。
    • キャプチャCallSiteのターゲットが呼び出されるときに発生し(一般的にinvokedynamicコール・サイトによって)、関数オブジェクトを生成します。 これは、単一ファクトリCallSiteに対して何度も発生する場合があります。 キャプチャでは、新しい関数オブジェクトが割り当てられたり、既存の関数オブジェクトを返したりすることもあります。 動作MethodHandleには、指定されたインタフェース・メソッドのパラメータ以外に追加パラメータが指定される場合があります。これらはキャプチャ・パラメータと呼ばれ、CallSiteターゲットへの引数として指定される必要があり、動作MethodHandleに早期バインドされる場合があります。 キャプチャ・パラメータの数および型はリンケージ中に決定されます。
    • 呼出し。実装されたインタフェース・メソッドが関数オブジェクトで呼び出されたときに発生します。 これは、単一関数オブジェクトに対して何度も発生する場合があります。 動作MethodHandleによって参照されるメソッドは、MethodHandle.invoke(Object...)による場合と同様に、キャプチャ引数と呼出しで指定される追加引数を使用して呼び出されます。

    呼出しで許可される入力または結果のセットを制限することが便利な場合があります。 たとえば、ジェネリック・インタフェース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を参照してください。

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

    • invokedType (CallSiteシグネチャを記述)は、型(D1..Dk)および戻り型RdのKパラメータを持つ。
    • samMethodType (実装されたメソッド型を記述)は、型(U1..Un)および戻り型RuのNパラメータを持つ。
    • implMethod (実装を提供するMethodHandle)は、型(A1..Am)および戻り型RaのMパラメータを持つ(メソッドがインスタンス・メソッドを記述する場合、このメソッド・ハンドルのメソッド型はレシーバに対応する追加の最初の引数をすでに含む)。
    • instantiatedMethodType (呼出しでの制限を許可)は、型(T1..Tn)および戻り型RtのNパラメータを持つ。

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

    • Rdがインタフェース
    • implMethod直接メソッド・ハンドル
    • samMethodTypeおよびinstantiatedMethodTypeが同じ引数カウント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に適応可能

    さらに、キャプチャ時は、implMethodがインスタンス・メソッドに対応し、キャプチャ引数(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
    • フィールドのサマリー

      フィールド 
      修飾子と型 フィールド 説明
      static int FLAG_BRIDGES
      ラムダ・オブジェクトが追加のブリッジ・メソッドを必要としていることを示す、代替メタファクトリ用のフラグ
      static int FLAG_MARKERS
      ラムダ・オブジェクトがSerializable以外に他のマーカー・インタフェースを実装することを示す、代替メタファクトリ用のフラグ
      static int FLAG_SERIALIZABLE
      ラムダ・オブジェクトが直列化可能である必要があることを示す、代替メタファクトリ用のフラグ
    • フィールドの詳細

      • FLAG_SERIALIZABLE

        public static final int FLAG_SERIALIZABLE
        ラムダ・オブジェクトが直列化可能である必要があることを示す、代替メタファクトリ用のフラグ
        関連項目:
        定数フィールド値
      • FLAG_MARKERS

        public static final int FLAG_MARKERS
        ラムダ・オブジェクトがSerializable以外に他のマーカー・インタフェースを実装することを示す、代替メタファクトリ用のフラグ
        関連項目:
        定数フィールド値
      • FLAG_BRIDGES

        public static final int FLAG_BRIDGES
        ラムダ・オブジェクトが追加のブリッジ・メソッドを必要としていることを示す、代替メタファクトリ用のフラグ
        関連項目:
        定数フィールド値
    • メソッドの詳細

      • metafactory

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

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

        このメソッドから返されるCallSiteのターゲットが呼び出されると、結果の関数オブジェクトは、invokedTypeの戻り型で指定されるインタフェースを実装し、かつinvokedNameで指定される名前とsamMethodTypeで指定されるシグネチャを持つメソッドを宣言する、クラスのインスタンスです。 Objectからの追加メソッドをオーバーライドすることもできます。

        パラメータ:
        caller - 呼出し元のアクセス可能性権限を持つルックアップ・コンテキストを表します。 invokedynamicで使用されるときは、これはVMによって自動的にスタックされます。
        invokedName - 実装するメソッドの名前。 invokedynamicで使用されるときは、これはInvokeDynamic構造のNameAndTypeによって提供され、VMによって自動的にスタックされます。
        invokedType - CallSiteの期待されるシグネチャ。 パラメータ型はキャプチャ変数の型を表し、戻り型は実装するインタフェースです。 invokedynamicで使用されるときは、これはInvokeDynamic構造のNameAndTypeによって提供され、VMによって自動的にスタックされます。 実装メソッドがインスタンス・メソッドで、このシグネチャがパラメータを持つ場合は、呼出しシグネチャの最初のパラメータはレシーバに対応する必要があります。
        samMethodType - 関数オブジェクトによって実装されるメソッドのシグネチャおよび戻り型。
        implMethod - 呼出しで(引数型および戻り型が適切に適応され、キャプチャ引数に呼出し引数が付加された状態で)呼び出される実装メソッドを記述する直接メソッド・ハンドル。
        instantiatedMethodType - 呼出しで動的に適用されるシグネチャおよび戻り型。 これは、samMethodTypeと同じ場合、またはその特殊化の場合があります。
        戻り値:
        CallSite。そのターゲットを使用してキャプチャを実行し、invokedTypeで指定されるインタフェースのインスタンスを生成できる
        例外:
        LambdaConversionException - 前述のリンケージ不変条件に違反する場合
      • altMetafactory

        public static CallSite altMetafactory​(MethodHandles.Lookup caller,
                                              String invokedName,
                                              MethodType invokedType,
                                              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 invokedName,
                                  MethodType invokedType,
                                  Object... args)
         

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

        
          CallSite altMetafactory(MethodHandles.Lookup caller,
                                  String invokedName,
                                  MethodType invokedType,
                                  MethodType samMethodType,
                                  MethodHandle implMethod,
                                  MethodType instantiatedMethodType,
                                  int flags,
                                  int markerInterfaceCount,  // IF flags has MARKERS set
                                  Class... markerInterfaces, // IF flags has MARKERS set
                                  int bridgeCount,           // IF flags has BRIDGES set
                                  MethodType... bridges      // IF flags has BRIDGES set
                                  )
         

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

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

        markerInterfacesで指定される各クラスには、前述invokedTypeの戻り型、Rdと同じ制限が適用されます。 bridgesで指定される各MethodTypeには、前述samMethodTypeと同じ制限が適用されます。

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

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

        • このクラスはinvokedTypeの戻り型で指定されるインタフェースと、markerInterfacesで指定されるインタフェースを実装します。
        • このクラスはinvokedNameで指定される名前、samMethodTypeで指定されるシグネチャ、およびbridgesで指定される追加シグネチャでメソッドを宣言します。
        • このクラスはObjectからのメソッドをオーバーライドでき、直列化に関連するメソッドを実装できます。
        パラメータ:
        caller - 呼出し元のアクセス可能性権限を持つルックアップ・コンテキストを表します。 invokedynamicで使用されるときは、これはVMによって自動的にスタックされます。
        invokedName - 実装するメソッドの名前。 invokedynamicで使用されるときは、これはInvokeDynamic構造のNameAndTypeによって提供され、VMによって自動的にスタックされます。
        invokedType - CallSiteの期待されるシグネチャ。 パラメータ型はキャプチャ変数の型を表し、戻り型は実装するインタフェースです。 invokedynamicで使用されるときは、これはInvokeDynamic構造のNameAndTypeによって提供され、VMによって自動的にスタックされます。 実装メソッドがインスタンス・メソッドで、このシグネチャがパラメータを持つ場合は、呼出しシグネチャの最初のパラメータはレシーバに対応する必要があります。
        args - 前述のaltMetafactory(MethodHandles.Lookup, String, MethodType, Object...)の説明のとおり、必要な引数samMethodTypeimplMethodinstantiatedMethodTypeおよびflagsとオプション引数を含むObject[]配列
        戻り値:
        CallSite。そのターゲットを使用してキャプチャを実行し、invokedTypeで指定されるインタフェースのインスタンスを生成できる
        例外:
        LambdaConversionException - 前述のリンケージ不変条件に違反する場合