Модуль jdk.dynalink
Dynalink — это библиотека для динамической компоновки высокоуровневых операций над объектами. К таким операциям относятся «прочитать свойство», «записать свойство», «вызвать функцию» и так далее. Dynalink особенно полезна при реализации языков программирования, в которых по крайней мере некоторые выражения имеют динамические типы (то есть типы, которые нельзя определить статически), а операции над динамическими типами представляются в виде точек вызова. Во время выполнения эти точки вызова будут связаны с подходящими целевыми дескрипторами методов на основе фактических типов значений, полученных при вычислении выражений. Они могут меняться между вызовами, что требует повторной компоновки точки вызова для учета новых типов; Dynalink берет на себя эту и другие задачи.
Dynalink поддерживает реализацию языков программирования с объектными моделями, отличающимися (в том числе радикально) от основанной на классах модели JVM, и собственными преобразованиями типов.
Dynalink тесно связана с пакетом java.lang.invoke и использует его.
Хотя пакет java.lang.invoke предоставляет низкоуровневый API для динамической компоновки точек вызова invokedynamic, он не предоставляет способа выражать высокоуровневые операции над объектами и методы, реализующие их. Это типичные операции в объектно-ориентированных средах: доступ к свойствам, доступ к элементам коллекций, вызов методов и конструкторов (возможно, с множественной диспетчеризацией, например с эквивалентами разрешения перегрузки методов Java на этапе компоновки и во время выполнения). Все это функции, которые обычно требуются языкам на JVM. Если язык имеет статическую типизацию, а его система типов соответствует системе типов JVM, для этого можно использовать обычные инструкции вызова, доступа к полям и т. д. (например, invokevirtual, getfield). Однако если язык динамический (то есть типы некоторых выражений неизвестны до их вычисления во время выполнения) или его объектная модель либо система типов существенно отличается от модели 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 нужен метод начальной загрузки. Минималистичный метод начальной загрузки с 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. Слово «Relinkable» указывает на то, что если точка вызова во время выполнения сталкивается с объектами разных типов, ее цель будет заменена дескриптором метода, способным выполнить операцию над вновь обнаруженным типом.SimpleRelinkableCallSiteиChainedCallSite(не используемый в приведенном выше примере) — две реализации, уже предоставляемые библиотекой. - Dynalink использует объекты
CallSiteDescriptorдля сохранения параметров метода начальной загрузки: объекта поиска и типа метода, поскольку они понадобятся при повторной компоновке точки вызова. - Dynalink использует объекты
Operationдля представления динамических операций. При этом способ кодирования операций в точке вызова не регламентируется. Поэтому в приведенном выше примере функцияparseOperationоставлена пустой, а вам предлагается написать код, который разбирает строку"GET:PROPERTY:color"в имени точки вызова и создает объект операции получения именованного свойства, например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 может связывать все эти операции; рекомендуется как минимум поддерживать и использовать их и в вашем языке. Стандартные операции GET и SET необходимо объединять как минимум с одним объектом Namespace, чтобы их можно было использовать. Например, для представления получения свойства следует использовать StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY). Dynalink определяет три стандартных пространства имен в классе StandardNamespace. Чтобы связать операцию с фиксированным именем, можно использовать NamedOperation, как в предыдущем примере: StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color") представляет получение свойства с именем «color». Операции в нескольких пространствах имен
В некоторых языках пространства имен объектов для свойств, элементов и методов не разделены, поэтому языковая конструкция может обращаться сразу к нескольким из них. Dynalink поддерживает указание нескольких объектовNamespace с помощью NamespaceOperation. Компоновщики для конкретных языков
Языкам, которые определяют собственную объектную модель, отличающуюся от основанной на классах модели JVM, и/или используют собственные преобразования типов, потребуется создать собственные компоновщики для конкретного языка. Чтобы начать работу, ознакомьтесь с пакетомjdk.dynalink.linker и, в частности, с интерфейсом GuardingDynamicLinker. Dynalink и объекты Java
ОбъектыDynamicLinker, создаваемые по умолчанию с помощью DynamicLinkerFactory, содержат внутренний экземпляр BeansLinker — компоновщика для конкретного языка, реализующего обычную семантику Java для всех перечисленных выше операций и способного связывать любые объекты Java, которые не удалось связать другим компоновщикам для конкретных языков. Таким образом, все среды выполнения языков имеют встроенную возможность взаимодействия с обычными объектами Java. Подробные сведения о связывании различных операций см. в разделе BeansLinker. Межъязыковое взаимодействие
ДляDynamicLinkerFactory можно задать загрузчик классов. Он попытается создать экземпляры всех классов GuardingDynamicLinkerExporter, доступных этому загрузчику классов, и включить предоставляемые ими компоновщики в создаваемый DynamicLinker. Это обеспечивает взаимодействие между языками: если в JVM развернуты среды выполнения двух языков A и B и они экспортируют свои компоновщики описанным выше способом, в объектах DynamicLinker каждой среды выполнения будет находиться экземпляр компоновщика для конкретного языка другой среды. Это означает, что если объект из среды выполнения языка B передается коду среды выполнения языка A, компоновщик из B получит возможность связать точку вызова в A при обнаружении объекта из B.Пакеты
| Пакет | Описание |
|---|---|
| jdk.dynalink | Содержит интерфейсы и классы, используемые для связывания точки вызова invokedynamic. |
| jdk.dynalink.beans | Содержит компоновщик для обычных объектов Java. |
| jdk.dynalink.linker | Содержит интерфейсы и классы, необходимые средам выполнения языков для реализации собственных объектных моделей и преобразований типов. |
| jdk.dynalink.linker.support | Содержит классы, упрощающие реализацию собственных объектных моделей и преобразований типов в средах выполнения языков: они предоставляют базовые реализации некоторых классов, а также различные служебные средства. |
| jdk.dynalink.support | Содержит классы, упрощающие использование Dynalink: они предоставляют базовые реализации некоторых классов, а также различные служебные средства. |
Службы
| Тип | Описание |
|---|---|
| GuardingDynamicLinkerExporter | Класс, предоставляющий защищенные динамические компоновщики, которые могут автоматически загружаться другими средами выполнения языков. |
© 1993, 2025, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/25/docs/api/jdk.dynalink/module-summary.html