Модуль 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. «Перепривязка» здесь подразумевает тот факт, что если узел вызова сталкивается с объектами разных типов во время выполнения, его целевой обработчик методов будет изменён на обработчик методов, который может выполнить операцию с вновь встреченным типом.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") выражает оператор получения для свойства с именем «цвет». Операции с несколькими пространствами имён
Некоторые языки могут не иметь отдельных пространств имён для свойств, элементов и методов для объектов, а конструкция исходного языка может одновременно обращаться к нескольким из них. Dynalink поддерживает указание нескольких объектовNamespace с помощью NamespaceOperation. Языкоспецифичные привязки
Языки, которые определяют свою собственную модель объектов, отличную от модели JVM, основанной на классах, и/или используют свои собственные преобразования типов, должны создать свои собственные языкоспецифичные привязки. Обратитесь к пакетуjdk.dynalink.linker и, в частности, к интерфейсу GuardingDynamicLinker для начала работы. Dynalink и объекты Java
DynamicLinker объекты, созданные DynamicLinkerFactory по умолчанию, содержат внутренний экземпляр BeansLinker, который является языкоспецифичной привязкой, реализующей обычные семантики Java для всех вышеперечисленных операций и может привязывать любой объект Java, к которому не удалось привязаться ни одной другой языкоспецифичной привязке. Таким образом, все среды выполнения языков имеют встроенную взаимозаменяемость с обычными объектами Java. Подробности о том, как он привязывает различные операции, см. в BeansLinker. Взаимодействие языков
ADynamicLinkerFactory может быть настроен с помощью загрузчика классов. Он будет пытаться создать все GuardingDynamicLinkerExporter классы, видимые для этого загрузчика классов, и объединит предоставляемые ими привязки в DynamicLinker, который он создаёт. Это позволяет взаимодействовать между языками: если у вас есть две среды выполнения языков A и B, развернутые в вашей 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://download.java.net/java/early_access/jdk24/docs/api/jdk.dynalink/module-summary.html