モジュール jdk.dynalink

高水準の操作をオブジェクトに動的にリンクするためのAPIを定義します。

Dynalinkは、オブジェクトに対する高レベル操作の動的リンクのためのライブラリです。 これらの操作には、"物件を読む"、"プロパティを書く"、"関数を呼び出す"などがあります。 Dynalinkは、少なくともいくつかの式が動的型(つまり、静的に決定できないタイプ)を持ち、動的型の操作が「コール・サイト」として表されるプログラミング言語を実装するために主に役立ちます。 これらのコール・サイトは、式が評価された実際のタイプの値に基づいて、実行時に適切なターゲット「メソッド・ハンドル」にリンクされます。 これらは呼び出し間で変更される可能性があり、新しい型に対応するために呼び出しサイトを複数回再リンクする必要があります。Dynalinkはそのすべてを処理します。

Dynalinkは、JVMクラス・ベースのモデルと異なる(根本的に)を持つオブジェクト・モデルでプログラミング言語の実装をサポートし、カスタム型変換を行います。

Dynalinkはjava.lang.invokeパッケージと密接に関連しており、依存しています。

java.lang.invokeinvokedynamic呼び出しサイトの動的リンク用の低レベルのAPIを提供しますが、オブジェクトやそれを実装するメソッドでは、より高いレベルの操作を表現する方法を提供しません。 これらの操作は、オブジェクト指向環境における通常の操作です: プロパティ・アクセス、コレクション要素のアクセス、メソッドとコンストラクタの呼び出し(潜在的に複数のディスパッチ、例えばJavaオーバーロードされたメソッド解決のリンクとランタイムに相当)。 これらは、JVM上の言語で通常必要とされるすべての機能です。 言語が静的に型付けされ、その型システムがJVMのものと一致する場合、通常の呼び出し、フィールド・アクセスなどの命令を使用してこれを実行できます。(e.g. invokevirtual, getfield)。 しかし、言語が動的な(したがって、実行時に評価されるまで、一部の式の型がわからない)、またはそのオブジェクト・モデルまたは型システムがJVMのものと密接に一致しない場合は、代わりにinvokedynamic呼び出しサイトを使用して、Dynalinkでそれらを管理する必要があります。

Dynalinkはおそらくその使用方法を示す例で最もよく説明されています。 たとえば、オブジェクトの型を宣言する必要がなく、そのオブジェクトのプロパティにアクセスしたいという言語のプログラムがあるとします:
 var color = obj.color;
 
上記の1行のプログラムを表すJavaクラスを生成した場合、そのバイトコードは次のようになります:
 aload 2 // load "obj" on stack
 invokedynamic "GET:PROPERTY:color"(Object)Object // invoke property getter on object of unknown type
 astore 3 // store the return value into local variable "color"
 
invokedynamic命令をリンクするには、ブートストラップ方式が必要です。 Dynalinkを使った最小限のブートストラップ・メソッドは、次のようになります:
 import java.lang.invoke.*;
 import jdk.dynalink.*;
 import jdk.dynalink.support.*;

 class MyLanguageRuntime {
     private static final DynamicLinker dynamicLinker = new DynamicLinkerFactory().createLinker();

     public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
         return dynamicLinker.link(
             new SimpleRelinkableCallSite(
                 new CallSiteDescriptor(lookup, parseOperation(name), type)));
     }

     private static Operation parseOperation(String name) {
         ...
     }
 }
 
上記のコード・スニペットには、いくつかの重要なオブジェクトがあります:
  • DynamicLinkerはDynalinkの主なオブジェクトであり、呼び出されたサイトの名前付き操作を実装するメソッド・ハンドルへの呼び出しサイトのリンクを調整します。 これは、DynamicLinkerFactoryを使用して構成および作成されます。
  • ブートストラップ・メソッドが呼び出されると、CallSiteオブジェクトを作成する必要があります。 Dynalinkでは、これらのコール・サイトではさらにRelinkableCallSiteインタフェースを実装する必要があります。 "再リンク可能な"は、実行時にコール・サイトが異なる型のオブジェクトに遭遇した場合、そのターゲットは、新しく遭遇した型で操作を実行できるメソッド・ハンドルに変更されるという事実を暗示しています。 SimpleRelinkableCallSiteChainedCallSite (上記の例では使用されていません)はすでにライブラリによって提供されている2つの実装です。
  • Dynalinkは、CallSiteDescriptorオブジェクトを使用して、ブートストラップ・メソッドのパラメータを保持: コール・サイトを再リンクする必要があるときはいつでも必要となるため、ルックアップとメソッドの型が異なります。
  • Dynalinkは動的操作を表現するためにOperationオブジェクトを使用します。 ただし、コール・サイトでどのように操作をエンコードするかは規定していません。 そのため、上記の例では、parseOperation関数が空のままであり、コール・サイト名の文字列"GET:PROPERTY:color"を構文解析するコードを、StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")という名前のプロパティ・ゲッター操作オブジェクトに渡す必要があります。

すでに上記の設定で何ができますか? DynamicLinkerFactoryは、デフォルトでJavaオブジェクトと通常のJavaセマンティクスをリンクできるDynamicLinkerを作成します。 これらの3つの単純なクラスがある場合:

 public class A {
     public String color;
     public A(String color) { this.color = color; }
 }

 public class B {
     private String color;
     public B(String color) { this.color = color; }
     public String getColor() { return color; }
 }

 public class C {
     private int color;
     public C(int color) { this.color = color; }
     public int getColor() { return color; }
 }
 
何らかの形でインスタンスを作成し、それらのインスタンスをプログラミング言語でコール・サイトに渡します:
 for each(var obj in [new A("red"), new B("green"), new C(0x0000ff)]) {
     print(obj.color);
 }
 
最初の呼び出しでDynalinkは.colorゲッター操作をA.colorのフィールド・ゲッターにリンクし、2回目の呼び出しではStringを戻すB.getColor()にリリンクし、3回目の呼び出しではC.getColor()に戻してintを返します。 上記で使用したSimpleRelinkableCallSiteは、最後に検出された型(それは「単相インライン・キャッシュ」として知られているものを実装)のリンケージを覚えています。 すでに提供されている別の実装では、ChainedCallSiteはいくつかの異なるタイプのリンケージを思い出します。おそらく深刻なアプリケーションではより良い選択です。

Dynalinkとバイトコードの作成

CallSiteオブジェクトは、通常、バイトコード内のinvokedynamic命令のブートストラップの一部として作成されます。 したがって、Dynalinkは、通常、プログラムをJavaの.classバイトコード形式にコンパイルする言語ランタイムの一部として使用されます。 Dynalinkは、バイトコード・クラスを作成するか、またはそれらをJVMにロードする側面に対処していません。 つまり、Dynalinkは、CallSiteオブジェクトを明示的に作成し、それを解釈されたプログラム(例えば、代表的な表現は、構文木のいくつかのノード・オブジェクトである)の動的操作の表現に関連付けることによって、バイトコードのコンパイルなしで使用することもできます((例:言語インタープリタ))。

利用可能な操作

Dynalinkは、StandardOperationクラスでいくつかの標準操作を定義しています。 Javaオブジェクトのリンカーは、これらの操作のすべてをリンクすることができます。これらの操作は、少なくともあなたの言語でサポートし、使用することをお勧めします。 標準操作のGETSETは、例えばプロパティ・ゲッターを表現するために、少なくとも1つのNamespaceと組み合わせて使用する必要があります。StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY)を使用します。 Dynalinkは、StandardNamespaceクラスに3つの標準ネームスペースを定義しています。 固定名を操作に関連付けるには、前の例のようにNamedOperationを使用できます: StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")は、"color"という名前のプロパティのゲッターを表します。

複数のネームスペースに対する操作

言語によっては、プロパティ、要素、およびメソッドのオブジェクトに別々のネームスペースを持たないものもあります。 Dynalinkは、複数のNamespaceオブジェクトをNamespaceOperationで指定することをサポートしています。

言語固有のリンカー

JVMクラス・ベースのモデルとは異なる独自のオブジェクト・モデルを定義したり、独自の型変換を使用する言語は、独自の言語固有のリンカーを作成する必要があります。 開始するには、jdk.dynalink.linkerパッケージ、特にGuardingDynamicLinkerインタフェースを参照してください。

DynalinkとJavaオブジェクト

デフォルトでDynamicLinkerFactoryによって作成されたDynamicLinkerオブジェクトには、上記の操作のすべてに対して通常のJavaセマンティクスを実装する言語固有のリンカーであるBeansLinkerの内部インスタンスが含まれており、他の言語固有のリンカーが管理していないJavaオブジェクト・リンク。 このように、すべての言語ランタイムには、通常のJavaオブジェクトとの相互運用性が組み込まれています。 さまざまな操作をリンクする方法の詳細については、BeansLinkerを参照してください。

言語間の相互運用性

DynamicLinkerFactory「クラス・ローダー」で構成することができます。 そのクラス・ローダーに見えるすべてのGuardingDynamicLinkerExporterクラスをインスタンス化し、それが作成するDynamicLinkerに与えるリンカーを作成しようとします。 これにより、言語間の相互運用性が可能になります: JVMに2つの言語ランタイムAとBがデプロイされていて、リンカーを上記のメカニズムでエクスポートすると、言語ランタイムAはBからの言語固有のリンカー・インスタンスを持ち、DynamicLinkerオブジェクトではその逆のリンカー・インスタンスを持ちます。 つまり、言語ランタイムBのオブジェクトが言語ランタイムAのコードに渡された場合、BのリンカーはBのオブジェクトに出会ったときにAの呼び出しサイトをリンクする機会を得ます。
モジュール・グラフ:
jdk.dynalinkのモジュール・グラフjdk.dynalinkのモジュール・グラフ
導入されたバージョン:
9