ナビゲーション・リンクをスキップ
Java(tm) Platform
Standard Edition 8

パッケージ java.lang.invoke

java.lang.invokeパッケージには、Javaコア・クラス・ライブラリおよび仮想マシンによって直接提供される動的言語サポートが含まれています。

参照: 説明

パッケージjava.lang.invokeの説明

java.lang.invokeパッケージには、Javaコア・クラス・ライブラリおよび仮想マシンによって直接提供される動的言語サポートが含まれています。

Java仮想マシン仕様で説明されているように、このパッケージ内の特定の型と、仮想マシンの動的言語サポートには、特別な関係があります。

Java仮想マシンの関連する変更点のサマリー

次の低レベル情報は、Java仮想マシン仕様の関連部分のサマリーです。完全な詳細については、この仕様の現在のバージョンを参照してください。invokedynamic命令の個々の出現は動的コール・サイトと呼ばれます。

invokedynamic命令

動的コール・サイトは最初はリンクされていない状態です。この状態では、コール・サイトが呼び出すべきターゲット・メソッドは存在しません。

JVMが動的コール・サイト(invokedynamic命令)を実行するには、そのコール・サイトをまずリンクする必要があります。リンクはブートストラップ・メソッドを呼び出すことで実現されますが、このメソッドは、与えられたコール・サイトの静的な情報コンテンツに基づいて、コール・サイトの動作を与えるメソッド・ハンドルを生成する必要があります。

invokedynamic命令は、自身のブートストラップ・メソッドを定数プール参照として静的に指定します。invokevirtualやその他の呼出し命令の場合とまったく同じく、この定数プール参照はコール・サイトの名前と型記述子も指定します。

リンク処理ではまず、ブートストラップ・メソッドの定数プール・エントリの解決と、動的コール・サイトの型記述子のMethodTypeオブジェクトの解決が行われます。この解決プロセスでクラスのロード処理がトリガーされる可能性があります。したがって、クラスのロードに失敗した場合に、エラーがスローされる可能性があります。このエラーは、動的コール・サイト実行の異常終了になります。リンクではクラスの初期化はトリガーされません。

ブートストラップ・メソッドの呼出し時には少なくとも3つの値が渡されます。

呼出しは、MethodHandle.invokeを使用したかのように行われます。返される結果は、CallSite (またはサブクラス)でなければいけません。このコール・サイトのターゲットの型は、動的コール・サイトの型記述子から派生されてブートストラップ・メソッドに渡された型と、厳密に等しくなければいけません。このコール・サイトはその後、その動的コール・サイトに永続的にリンクされた状態になります。

JVM仕様にドキュメント化されているように、動的コール・サイトのリンクに起因する失敗はすべてBootstrapMethodErrorとして報告されますが、これは、動的コール・サイト実行の異常終了としてスローされます。これが発生した場合、動的コール・サイトを実行する後続のすべての試みで、同じエラーがスローされます。

リンクのタイミング

動的コール・サイトがリンクされるのは、その最初の実行の直前です。リンクを実装するブートストラップ・メソッドの呼出しが発生するのは、最初の実行を試みているスレッド内です。

そのようなスレッドがいくつか存在する場合、ブートストラップ・メソッドがいくつかのスレッド内で並行して呼び出される可能性があります。したがって、グローバル・アプリケーション・データにアクセスするブートストラップ・メソッドでは、競合状態に対する通常の予防策を講じる必要があります。いずれにせよ、すべての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.invokeまたはinvokeWithArgumentsのいずれかを使用したかのように行われます。(その違いを区別する方法はありません。)

MethodHandle.invokeの通常の引数変換ルールが、スタック内のすべての引数に適用されます。たとえば、プッシュされる値がプリミティブ型であった場合、それはボクシング変換によって参照に変換される可能性があります。ブートストラップ・メソッドが可変引数メソッドである(修飾子ビット0x0080が設定されている)場合、ここに指定された引数の一部または全部が末尾の配列パラメータ内に集められる可能性があります。(これは特殊なルールでなく、CONSTANT_MethodHandle定数、可変引数メソッド用の修飾子ビット、およびasVarargsCollector変換の間の相互作用の有用な結果です。)

以上のルールに基づき、追加引数のさまざまな個数Nごとに、正しいブートストラップ・メソッド宣言の例を次に示します。最初の数行(*の付いたもの)は、任意の数の追加引数で動作します。

Nサンプルのブートストラップ・メソッド
*CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)
*CallSite bootstrap(Object... args)
*CallSite bootstrap(Object caller, Object... nameAndTypeWithArgs)
0CallSite bootstrap(Lookup caller, String name, MethodType type)
0CallSite bootstrap(Lookup caller, Object... nameAndType)
1CallSite bootstrap(Lookup caller, String name, MethodType type, Object arg)
2CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)
2CallSite bootstrap(Lookup caller, String name, MethodType type, String... args)
2CallSite bootstrap(Lookup caller, String name, MethodType type, String x, int y)
最後の例では、追加引数の型がそれぞれCONSTANT_StringCONSTANT_Integerであると仮定しています。最後から2番目の例では、すべての追加引数の型がCONSTANT_Stringであると仮定しています。その他の例は、あらゆる型の追加引数で動作します。

前述したように、ブートストラップ・メソッドの実際のメソッド型は変更可能です。たとえば、4番目の引数はMethodHandleでもかまいません(それがCONSTANT_InvokeDynamicエントリ内の対応する定数の型である場合)。その場合、MethodHandle.invokeの呼出しでは追加メソッド・ハンドル定数がObjectとして渡されますが、MethodHandle.invokeの型一致機構によってその参照が元のMethodHandleにキャストされたあと、ブートストラップ・メソッドが呼び出されます。(不適切に生成されたコードによって文字列定数が代わりに渡された場合、そのキャストは失敗し、BootstrapMethodErrorが発行されます。)

上記のルールの結果として、ブートストラップ・メソッドを定数プール・エントリで表現できる場合は、それがプリミティブ引数を受け入れる可能性があることに注意してください。ただし、型がbooleanbyteshort、またはcharの引数をブートストラップ・メソッド用に作成することはできず(そのような定数を定数プールで直接表現することができないため)、ブートストラップ・メソッドを呼び出しても必要なナロー・プリミティブ変換は行われません。

ブートストラップ・メソッドの追加引数の目的は、言語実装者がメタデータのエンコードを安全かつコンパクトに行えるようにすることです。原則として名前引数や追加引数は冗長になりますが、それは、各コール・サイトにそれぞれ一意のブートストラップ・メソッドが指定される可能性があるからです。そのような運用ではおそらく、大きなクラス・ファイルや定数プールが生成されます。

導入されたバージョン:
1.7
ナビゲーション・リンクをスキップ
Java(tm) Platform
Standard Edition 8

バグまたは機能を送信
詳細なAPIリファレンスおよび開発者ドキュメントについては、Java SEのドキュメントを参照してください。そのドキュメントには、概念的な概要、用語の定義、回避方法、有効なコード例などの、開発者を対象にしたより詳細な説明が含まれています。
Copyright © 1993, 2017, Oracle and/or its affiliates. All rights reserved. Use is subject to license terms. Documentation Redistribution Policyも参照してください。