パッケージ java.lang.invoke
java.lang.invoke
パッケージには、Javaコア・クラス・ライブラリおよび仮想マシンによって直接提供される動的言語サポートが含まれています。
Java仮想マシン仕様で説明されているように、このパッケージ内の特定の型と、仮想マシンの動的言語サポートには、特別な関係があります。
- クラス
MethodHandle
VarHandle
には、型記述子に関係なくリンクできる「シグネチャ・ポリモーフィック・メソッド」が含まれています。 通常、メソッドのリンク時には型記述子が厳密に一致する必要があります。 - JVMのバイト・コード形式では、クラス
MethodHandle
とMethodType
の即値定数がサポートされます。
Java仮想マシンの関連する変更点のサマリー
次の低レベル情報は、Java仮想マシン仕様の関連部分のサマリーです。 完全な詳細については、この仕様の現在のバージョンを参照してください。invokedynamic
命令の個々の出現は動的コール・サイトと呼ばれます。
invokedynamic
命令
動的コール・サイトは最初はリンクされていない状態です。 この状態では、コール・サイトが呼び出すべきターゲット・メソッドは存在しません。
JVMが動的コール・サイト(invokedynamic
命令)を実行するには、そのコール・サイトをまずリンクする必要があります。 リンクはブートストラップ・メソッドを呼び出すことで実現されますが、このメソッドは、与えられたコール・サイトの静的な情報コンテンツに基づいて、コール・サイトの動作を与えるメソッド・ハンドル
を生成する必要があります。
各invokedynamic
命令は、自身のブートストラップ・メソッドを定数プール参照として静的に指定します。 invokevirtual
やその他の呼出し命令の場合とまったく同じく、この定数プール参照はコール・サイトの名前と型記述子も指定します。
リンク処理ではまず、ブートストラップ・メソッドの定数プール・エントリの解決と、動的コール・サイトの型記述子のMethodType
オブジェクトの解決が行われます。 この解決プロセスでクラスのロード処理がトリガーされる可能性があります。 したがって、クラスのロードに失敗した場合に、エラーがスローされる可能性があります。 このエラーは、動的コール・サイト実行の異常終了になります。 リンクではクラスの初期化はトリガーされません。
ブートストラップ・メソッドの呼出し時には少なくとも3つの値が渡されます。
MethodHandles.Lookup
(動的コール・サイトの発生元である呼出し元クラス上のルックアップ・オブジェクト)String
(コール・サイト内で言及されたメソッド名)MethodType
(呼出しの解決済みの型記述子)- オプションで、定数プールから取得された任意の数の追加の静的引数
どのような場合でも、ブートストラップ・メソッドの呼び出しは、MethodHandle.invokeWithArguments
、(引数の数が十分に少ない場合、これは「ジェネリック呼び出し」と同じです。)
invokedynamic
命令の場合、返される結果はCallSite
へのnull以外の参照に変換可能でなければなりません。 返された結果を期待される型に変換できない場合は、BootstrapMethodError
がスローされます。 コール・サイト・ターゲットの型は、動的呼び出しサイト型記述子から派生した型と正確に等しく、ブートストラップ・メソッドに渡さなければなりません。そうでない場合は、BootstrapMethodError
がスローされます。 成功すると、コール・サイトはダイナミック・コール・サイトに永続的にリンクされます。
コール・サイトをリンクするときに例外、E
が発生すると、リンケージは失敗し、異常終了します。 E
の型がError
またはサブクラスである場合、E
は再スローされます。そうでない場合は、E
をラップするBootstrapMethodError
がスローされます。 この場合、ダイナミック・コール・サイトを実行しようとするすべての試行で、同じError
またはサブクラスがスローされます。
リンクのタイミング
動的コール・サイトがリンクされるのは、その最初の実行の直前です。 リンクを実装するブートストラップ・メソッドの呼出しが発生するのは、最初の実行を試みているスレッド内です。
そのようなスレッドがいくつか存在する場合、ブートストラップ・メソッドがいくつかのスレッド内で並行して呼び出される可能性があります。 したがって、グローバル・アプリケーション・データにアクセスするブートストラップ・メソッドでは、競合状態に対する通常の予防策を講じる必要があります。 いずれにせよ、すべてのinvokedynamic
命令は、リンクされていない状態、一意のCallSite
オブジェクトにリンクされた状態、のいずれかになります。
個別に変更可能な動作を備えた動的コール・サイトが必要なアプリケーションでは、ブートストラップ・メソッドはそれぞれ異なるCallSite
オブジェクトを生成すべきです(リンク要求ごとに1つずつ)。 また、アプリケーションでは単一のCallSite
オブジェクトをいくつかのinvokedynamic
命令にリンクすることもできますが、その場合、ターゲット・メソッドへの変更がすべての命令で可視になります。
単一の動的コール・サイトのブートストラップ・メソッドがいくつかのスレッド内で同時に実行された場合、JVMは1つのCallSite
オブジェクトを選択し、それをすべてのスレッドにインストールして可視状態にする必要があります。 ほかのすべてのブートストラップ・メソッド呼出しは完了まで実行を許可されますが、それらの結果は無視され、それらの動的コール・サイト呼出しは、最初に選択されたターゲット・オブジェクトを使って処理されます。
解説: これらのルールにより、JVMが動的コール・サイトの複製や「偶発的な」ブートストラップ・メソッド呼出しの発行を行えるようになるわけではありません。 どの動的コール・サイトでも、未リンクからリンク済みへの遷移は、最初の呼出しの直前に最大1回しか行われません。 完了したブートストラップ・メソッド呼出しの効果を取り消す方法はありません。
ブートストラップ・メソッドの種類
各ブートストラップ・メソッドがMethodHandle.invoke
で正しく呼び出せるかぎり、その詳細な型は任意となります。 たとえば、最初の引数をMethodHandles.Lookup
ではなくObject
にしてもかまいませんし、戻り値の型もCallSite
ではなくObject
にすることができます。 (スタック内の引数の型と数により、適合するブートストラップ・メソッドの種類が、CallSite
サブクラスの適切に型付けされたstaticメソッドおよびコンストラクタに制限されます。)
特定のinvokedynamic
命令に静的な引数が1つも指定されていない場合、その命令のブートストラップ・メソッドが3つの引数(命令の呼出し元クラス、名前、およびメソッド型)で呼び出されます。 invokedynamic
命令に1つ以上の静的引数が指定されている場合、それらの値は追加の引数としてメソッド・ハンドルに渡されます。 (どのメソッドに対しても255個の制限があるので、可変長ブートストラップ以外のメソッドには最大251個の余分な引数を渡すことができます。ブートストラップ・メソッド自体とその最初の3つの引数も積み重ねる必要があるからです。) ブートストラップ・メソッドは、MethodHandle.invokeWithArguments
によって呼び出されます。 可変アリティ・ブートストラップ法は、数千の静的引数を受け入れることができ、クラス・ファイル形式によって課される制限によってのみ適用されます。
MethodHandle.invoke
の通常の引数変換ルールが、スタック内のすべての引数に適用されます。 たとえば、プッシュされる値がプリミティブ型であった場合、それはボクシング変換によって参照に変換される可能性があります。 ブートストラップ・メソッドが可変引数メソッドである(修飾子ビット0x0080
が設定されている)場合、ここに指定された引数の一部または全部が末尾の配列パラメータ内に集められる可能性があります。 (これは特殊なルールでなく、CONSTANT_MethodHandle
定数、可変引数メソッド用の修飾子ビット、およびasVarargsCollector
変換の間の相互作用の有用な結果です。)
以上のルールに基づき、追加引数のさまざまな個数N
ごとに、正しいブートストラップ・メソッド宣言の例を次に示します。 最初の行(マークされた*
)は任意の数の余分な引数に対して機能します。
N | ブートストラップ・メソッドの例 |
---|---|
* |
|
0 |
|
1 |
CallSite bootstrap(Lookup caller, String name, MethodType type, Object arg) |
2 |
|
String
とInteger
(またはint
)型であると仮定しています。 2番目から最後の例では、余分な引数はすべてString
型であると仮定しています。 その他の例は、あらゆる型の追加引数で動作します。
前述したように、ブートストラップ・メソッドの実際のメソッド型は変更可能です。 たとえば、4番目の引数はMethodHandle
でもかまいません(それがCONSTANT_InvokeDynamic
エントリ内の対応する定数の型である場合)。 その場合、MethodHandle.invoke
の呼出しでは追加メソッド・ハンドル定数がObject
として渡されますが、MethodHandle.invoke
の型一致機構によってその参照が元のMethodHandle
にキャストされたあと、ブートストラップ・メソッドが呼び出されます。 (不適切に生成されたコードによって文字列定数が代わりに渡された場合、そのキャストは失敗し、BootstrapMethodError
が発行されます。)
上記のルールの結果として、ブートストラップ・メソッドを定数プール・エントリで表現できる場合は、それがプリミティブ引数を受け入れる可能性があることに注意してください。 ただし、型がboolean
、byte
、short
、またはchar
の引数をブートストラップ・メソッド用に作成することはできず(そのような定数を定数プールで直接表現することができないため)、ブートストラップ・メソッドを呼び出しても必要なナロー・プリミティブ変換は行われません。
ブートストラップ・メソッドの追加引数の目的は、言語実装者がメタデータのエンコードを安全かつコンパクトに行えるようにすることです。 原則として名前引数や追加引数は冗長になりますが、それは、各コール・サイトにそれぞれ一意のブートストラップ・メソッドが指定される可能性があるからです。 そのようなプラクティスは、大きなクラス・ファイルと定数プールを生成する可能性があります。
- 導入されたバージョン:
- 1.7
-
インタフェースのサマリー インタフェース 説明 MethodHandleInfo 直接メソッド・ハンドルをその構成要素シンボリック部分に解決することによって取得されるシンボリック参照。 -
クラスのサマリー クラス 説明 CallSite CallSite
は、ターゲット
と呼ばれる変数MethodHandle
のホルダーです。ConstantCallSite ConstantCallSite
は、永続的で決して変更できないターゲットを持つCallSite
です。LambdaMetafactory おそらく型適応と引数の部分評価の後に、指定されたMethodHandle
への委譲によって、1つ以上のインタフェースを実装する単純な関数オブジェクトの作成を容易にするメソッド。MethodHandle メソッド・ハンドルとは、ベースとなるメソッド、コンストラクタ、フィールド、または類似の低レベル操作に対する、直接実行可能な型付きの参照のことであり、オプションで引数や戻り値の変換も行います。MethodHandleProxies このクラスはstaticメソッドのみで構成され、メソッド・ハンドルをインタフェースなどのその他のJVM型に適応させるときに役立ちます。MethodHandles このクラスは、メソッド・ハンドルに対する処理を行うかメソッド・ハンドルを返すstaticメソッドだけで構成されます。MethodHandles.Lookup ルックアップ・オブジェクトは、メソッド・ハンドルの作成にアクセス・チェックが必要な場合のメソッド・ハンドル作成用ファクトリです。MethodType メソッド型は、メソッド・ハンドルが受け取ったり返したりする引数や戻り値の型、あるいはメソッド・ハンドルの呼出し元が渡したり期待したりする引数や戻り値の型を表します。MutableCallSite MutableCallSite
は、ターゲット変数の動作が通常のフィールドと同じであるようなCallSite
です。SerializedLambda ラムダ式の直列化された形式。StringConcatFactory おそらく型適応と引数の部分評価の後に既知の型の既知数の引数を効率的に連結するために使用できる文字列連結メソッドの作成を容易にするメソッド。SwitchPoint SwitchPoint
は、状態遷移をほかのスレッドに発行できるオブジェクトです。VarHandle VarHandleは、変数に対する、あるいはパラメータを用いて指定される変数の一群に対する、動的に強く型付けされた参照です。それら変数には、staticなフィールド、非staticなフィールド、配列の要素、ヒープの外側にあるデータ構造のコンポーネントなどが含まれます。VolatileCallSite VolatileCallSite
は、ターゲットの動作がvolatile変数と同じであるようなCallSite
です。 -
列挙型のサマリー 列挙型 説明 VarHandle.AccessMode VarHandleによって参照される変数へのアクセス方法を指定するアクセス・モードのセット。 -
例外のサマリー 例外 説明 LambdaConversionException LambdaConversionExceptionStringConcatException リンケージ・イン・バリアントが違反されると、StringConcatExceptionがStringConcatFactory
によってスローされます。WrongMethodTypeException コード内でメソッド・ハンドルを不正なメソッド型経由で呼び出そうとしたことを示すためにスローされます。