模块 jdk.dynalink

定义用于动态链接对象上的高级操作的API。

Dynalink是一个用于动态链接对象上的高级操作的库。 这些操作包括“读取属性”,“写入属性”,“调用函数”等。 Dynalink主要用于实现编程语言,其中至少一些表达式具有动态类型(即,无法静态决定的类型),动态类型的操作表示为call sites 这些调用站点将在运行时根据表达式计算的值的实际类型链接到适当的目标method handles 这些可以在调用之间进行更改,从而需要多次重新链接调用站点以适应新类型; Dynalink处理所有这些以及更多。

Dynalink支持使用与JVM的基于类的模型不同(甚至是根本上)的对象模型实现编程语言,并具有自定义类型转换。

Dynalink与java.lang.invoke软件包密切相关,并依赖于它。

虽然java.lang.invokeinvokedynamic呼叫站点的动态链接提供了低级API,但它没有提供表达对象的更高级别操作的方法,也没有提供实现它们的方法。 这些操作是面向对象环境中的常见操作:属性访问,集合元素的访问,方法和构造函数的调用(可能具有多个调度,例如Java重载方法解析的链接和运行时等效项)。 这些是JVM上的语言通常需要的所有函数。 如果语言是静态类型,其类型系统相匹配的是,JVM的,它可以与使用通常的调用,现场访问等指令完成这个(如invokevirtualgetfield )。 但是,如果语言是动态的(因此,某些表达式的类型直到在运行时计算才知道),或者它的对象模型或类型系统与JVM的类型不匹配,那么它应该使用invokedynamic调用站点而不是让Dynalink管理它们。

Dynalink最好用一个显示其用途的例子来解释。 假设你有一个语言的程序,你不必声明对象的类型,并且你想访问它上面的属性:
  var color = obj.color; 
如果您生成了一个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指令,我们需要一个bootstrap方法。 使用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进行配置和创建。
  • 调用bootstrap方法时,需要创建一个CallSite对象。 在Dynalink中,这些呼叫站点需要另外实现RelinkableCallSite接口。 “可重新链接”这里暗示如果调用站点在运行时遇到不同类型的对象,其目标将更改为可以对新遇到的类型执行操作的方法句柄。 SimpleRelinkableCallSiteChainedCallSite (在上面的示例中未使用)是库已经提供的两种实现。
  • Dynalink使用CallSiteDescriptor对象来保存引导方法的参数:查找和方法类型,因为只要需要重新链接调用站点,它就需要它们。
  • Dynalink使用Operation对象来表示动态操作。 但是,它没有规定如何编码呼叫站点中的操作。 这就是为什么在上面的示例中, parseOperation函数保留为空,并且您需要提供代码以将调用站点名称中的字符串"GET:PROPERTY:color"解析为命名属性getter操作对象StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")

你可以用上面的设置做什么? 默认情况下, DynamicLinkerFactory创建一个DynamicLinker ,它可以将Java对象与通常的Java语义链接起来。 如果你有这三个简单的类:

  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 ,在第二次调用,将它重新链接到B.getColor()返回String ,最后在第三次调用将它重新链接到C.getColor()返回一个int 我们上面使用的SimpleRelinkableCallSite只记得上次遇到的类型的链接(它实现了所谓的单态内联缓存 )。 另一个已经提供的实现, ChainedCallSite将记住几种不同类型的链接(它是一个多态内联缓存 ),并且在严肃的应用程序中可能是更好的选择。

Dynalink和字节码创建

CallSite对象通常作为字节码中的引导invokedynamic指令的一部分创建。 因此,Dynalink通常用作将程序编译为Java .class字节码格式的语言运行时的一部分。 Dynalink没有解决创建字节码类或将它们加载到JVM中的问题。 也就是说,Dynalink也可以在没有字节码编译的情况下使用(例如在语言解释器中),通过显式创建CallSite对象并将它们与解释程序中的动态操作的表示相关联(例如,典型的表示将是语法树中的一些节点对象)。

可用的操作

Dynalink在其StandardOperation类中定义了几个标准操作。 Java对象的链接器可以链接所有这些操作,并且鼓励您至少支持并以您的语言使用这些操作。 标准操作GETSET需要与至少一个Namespace组合以用于例如表达属性获取器,您将使用StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY) Dynalink在StandardNamespace类中定义了三个标准名称空间。 要将固定名称与操作相关联,可以使用NamedOperation ,如上例所示: StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")表示名为“color”的属性的getter。

多个名称空间的操作

某些语言可能在属性,元素和方法的对象上没有单独的命名空间,并且源语言构造可能同时处理其中的几个。 Dynalink支持使用NamespaceOperation指定多个Namespace对象。

语言特定的连接词

定义自己的对象模型的语言与基于JVM类的模型不同和/或使用自己的类型转换将需要创建自己的语言特定的链接器。 请参阅jdk.dynalink.linker包,特别是GuardingDynamicLinker接口以开始使用。

Dynalink和Java对象

默认情况下, BeansLinker创建的DynamicLinker对象包含DynamicLinkerFactory的内部实例,该实例是特定于语言的链接器,它实现上述所有操作的常用Java语义,并且可以链接任何其他语言特定的链接器未设置的Java对象。链接。 这样,所有语言运行时都具有与普通Java对象的内置互操作性。 有关如何链接各种操作的详细信息,请参阅BeansLinker

跨语言互操作性

DynamicLinkerFactory可以配置class loader 它将尝试实例化该类加载器可见的所有GuardingDynamicLinkerExporter类,并将它们提供的链接组成它创建的DynamicLinker 这允许语言之间的互操作性:如果您在JVM中部署了两个语言运行时A和B并且它们通过上述机制导出它们的链接器,则语言运行时A将在其DynamicLinker对象中具有来自B的语言特定链接器实例,反之亦然。 这意味着如果来自语言运行时B的对象从语言运行时A传递给代码,则来自B的链接器将在遇到来自B的对象时有机会链接A中的调用站点。
模块图:
Module graph for jdk.dynalinkModule graph for jdk.dynalink
从以下版本开始:
9