Spec-Zone.ru › OpenJDK 25

Пакет java.lang.invoke

package java.lang.invoke
Пакет java.lang.invoke предоставляет низкоуровневые примитивы для взаимодействия с виртуальной машиной Java.

Как описано в Спецификации виртуальной машины Java, некоторые типы в этом пакете обрабатываются виртуальной машиной особым образом:

  • Классы MethodHandle и VarHandle содержат полиморфные по сигнатуре методы, которые могут быть связаны независимо от их дескриптора типа. Обычно для связывания метода требуется точное совпадение дескрипторов типов.
  • Формат байт-кода JVM поддерживает непосредственные константы классов MethodHandle и MethodType.
  • Инструкция invokedynamic использует загрузочные константы MethodHandle для динамического разрешения объектов CallSite, задающих пользовательское поведение вызова метода.
  • Инструкция ldc использует загрузочные константы MethodHandle для динамического разрешения пользовательских значений констант.

Динамическое разрешение точек вызова и констант

Ниже приведены низкоуровневые сведения, обобщающие относящиеся к делу разделы спецификации виртуальной машины Java. Полную информацию см. в актуальной версии этой спецификации.

Динамически вычисляемые точки вызова

Инструкция invokedynamic изначально находится в несвязанном состоянии. В этом состоянии у инструкции нет целевого метода для вызова.

Прежде чем JVM сможет выполнить инструкцию invokedynamic, инструкцию необходимо сначала связать. Связывание выполняется вызовом загрузочного метода, которому передаются статические сведения о вызове и который должен создать CallSite, задающий поведение вызова.

Каждая инструкция invokedynamic статически указывает собственный загрузочный метод в виде ссылки на запись пула констант. Ссылка на запись пула констант также задаёт имя вызова и дескриптор типа метода, как и invokestatic и другие инструкции вызова.

Динамически вычисляемые константы

Пул констант может содержать константы с тегом CONSTANT_Dynamic, снабжённые загрузочными методами, выполняющими их разрешение. Такая динамическая константа изначально находится в неразрешённом состоянии. Прежде чем JVM сможет использовать динамически вычисляемую константу, её необходимо сначала разрешить. Разрешение динамически вычисляемой константы выполняется вызовом загрузочного метода, которому передаются статические сведения о константе и который должен создать значение типа, статически объявленного для этой константы.

Каждая динамически вычисляемая константа статически указывает собственный загрузочный метод в виде ссылки на запись пула констант. Ссылка на запись пула констант также задаёт имя константы и дескриптор типа поля, как и getstatic и другие инструкции обращения к полям. (Грубо говоря, динамически вычисляемая константа относится к динамически вычисляемой точке вызова так же, как CONSTANT_Fieldref относится к CONSTANT_Methodref.)

Выполнение загрузочных методов

Разрешение динамически вычисляемой точки вызова или константы начинается с разрешения следующих элементов из пула констант:
  • загрузочного метода, CONSTANT_MethodHandle
  • Class или MethodType, полученного из компонента типа дескриптора CONSTANT_NameAndType
  • статических аргументов, если они есть (обратите внимание, что статические аргументы сами могут быть динамически вычисляемыми константами)

Затем загрузочный метод вызывается так, как если бы был вызван MethodHandle.invoke, со следующими аргументами:

  • MethodHandles.Lookup — объект поиска для класса-вызывателя, в котором находится динамически вычисляемая константа или точка вызова
  • String — имя, указанное в CONSTANT_NameAndType
  • MethodType или Class — разрешённый дескриптор типа для CONSTANT_NameAndType
  • Class — разрешённый дескриптор типа константы, если это динамическая константа
  • дополнительные разрешённые статические аргументы, если они есть

Для динамически вычисляемой точки вызова возвращаемый результат должен быть ненулевой ссылкой на CallSite. Тип целевого объекта точки вызова должен точно совпадать с типом, полученным из дескриптора типа вызова и переданным загрузочному методу. Если эти условия не выполнены, выбрасывается BootstrapMethodError. В случае успеха точка вызова навсегда связывается с инструкцией invokedynamic.

Для динамически вычисляемой константы первый параметр загрузочного метода должен быть совместим с присваиванием к MethodHandles.Lookup. Если это условие не выполнено, выбрасывается BootstrapMethodError. В случае успеха результат загрузочного метода кэшируется как разрешённое значение константы.

Если во время выполнения загрузочного метода возникает исключение, например E, разрешение завершается неудачно и аварийно прекращается. Исключение E повторно выбрасывается, если тип E — это Error или его подкласс; в противном случае выбрасывается BootstrapMethodError, оборачивающий E. Если это происходит, при всех последующих попытках выполнить инструкцию invokedynamic или загрузить динамически вычисляемую константу будет выброшена та же ошибка.

Момент разрешения

Инструкция invokedynamic связывается непосредственно перед первым выполнением. Динамически вычисляемая константа разрешается непосредственно перед первым использованием (помещением в стек или связыванием в качестве параметра загрузочного метода). Вызов загрузочного метода, выполняющий связывание, происходит в потоке, который пытается выполнить инструкцию или использовать константу впервые.

Если таких потоков несколько, загрузочный метод может быть вызван одновременно в нескольких потоках. Поэтому загрузочные методы, обращающиеся к глобальным данным приложения, должны принимать обычные меры предосторожности против состояний гонки. В любом случае каждая инструкция invokedynamic либо не связана, либо связана с уникальным объектом CallSite.

В приложении, которому требуются инструкции invokedynamic с индивидуально изменяемым поведением, загрузочные методы должны создавать отдельные объекты CallSite для каждого запроса на связывание. В качестве альтернативы приложение может связать один объект CallSite с несколькими инструкциями invokedynamic; в этом случае изменение целевого метода станет видимым для каждой из этих инструкций.

Если несколько потоков одновременно выполняют загрузочный метод для одной динамически вычисляемой точки вызова или константы, JVM должна выбрать результат одного загрузочного метода и сделать его видимым для всех потоков. Всем остальным вызовам загрузочного метода разрешено завершиться, но их результаты игнорируются.

Обсуждение: Эти правила не позволяют JVM совместно использовать точки вызова или выполнять «беспричинные» вызовы загрузочных методов. Каждая инструкция invokedynamic не более одного раза переходит из несвязанного состояния в связанное непосредственно перед первым вызовом. Отменить результат завершённого вызова загрузочного метода невозможно.

Типы загрузочных методов

Для динамически вычисляемой точки вызова загрузочный метод вызывается с параметрами типов MethodHandles.Lookup, String, MethodType и типов любых статических аргументов; возвращаемый тип — CallSite.

Для динамически вычисляемой константы загрузочный метод вызывается с параметрами типов MethodHandles.Lookup, String, Class и типов любых статических аргументов; возвращаемый тип — это тип, представленный Class.

Поскольку MethodHandle.invoke допускает адаптацию между типом вызываемого метода и типом метода дескриптора загрузочного метода, объявление загрузочного метода может быть гибким. Для динамически вычисляемой константы первый тип параметра дескриптора загрузочного метода должен допускать присваивание к MethodHandles.Lookup; помимо этого ограничения, к загрузочным методам динамически вычисляемых точек вызова и динамически вычисляемых констант применима одинаковая степень гибкости. Примечание: это ограничение допускает возможность будущего вызова загрузочного метода только с типами параметров статических аргументов, что позволит использовать более широкий диапазон методов, совместимых со статическими аргументами (например, методов, которые не объявляют и не требуют параметры метаданных поиска, имени и типа).

Например, для динамически вычисляемой точки вызова первым аргументом может быть Object вместо MethodHandles.Lookup, а возвращаемым типом также может быть Object вместо CallSite. (Обратите внимание, что типы и количество аргументов в стеке ограничивают допустимые виды загрузочных методов статическими методами и конструкторами с соответствующими типами.)

Если помещаемое значение имеет примитивный тип, его можно преобразовать в ссылку с помощью упаковки. Если загрузочный метод является методом с переменным числом аргументов (установлен его бит-модификатор 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)
0
  • CallSite bootstrap(Lookup caller, String name, MethodType type)
  • CallSite bootstrap(Lookup caller, Object... nameAndType)
1 CallSite bootstrap(Lookup caller, String name, MethodType type, Object arg)
2
  • CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)
  • CallSite bootstrap(Lookup caller, String name, MethodType type, String... args)
  • CallSite bootstrap(Lookup caller, String name, MethodType type, String x, int y)
В последнем примере предполагается, что дополнительные аргументы имеют типы String и Integer (или int) соответственно. В предпоследнем примере предполагается, что все дополнительные аргументы имеют тип String. Остальные примеры подходят для дополнительных аргументов любых типов. Обратите внимание, что все примеры, кроме второго и третьего, также подходят для динамически вычисляемых констант, если изменить возвращаемый тип так, чтобы он соответствовал объявленному типу константы (например, Object, который всегда совместим).

Поскольку динамически вычисляемые константы могут передаваться загрузочным методам в качестве статических аргументов, ограничений на типы загрузочных аргументов нет. Однако аргументы типов boolean, byte, short или char нельзя непосредственно передать через записи пула констант CONSTANT_Integer, поскольку преобразования asType не выполняют необходимые сужающие преобразования примитивных типов.

В приведённых выше примерах возвращаемый тип всегда CallSite, но это не является обязательным свойством загрузочных методов. В случае динамически вычисляемой точки вызова требуется лишь, чтобы возвращаемый тип загрузочного метода можно было преобразовать (с помощью преобразований asType) в CallSite; это означает, что возвращаемый тип загрузочного метода может быть Object или ConstantCallSite. В случае динамически разрешаемой константы возвращаемый тип загрузочного метода должен преобразовываться в тип константы, представленный дескриптором её типа поля. Например, если динамическая константа имеет дескриптор типа поля "C" (char), возвращаемым типом загрузочного метода может быть Object, Character или char, но не int или Integer.

С версии:
1.7
Пакет Описание
java.lang
Содержит классы, фундаментальные для проектирования языка программирования Java.
Класс Описание
CallSite
CallSite — это контейнер для переменной MethodHandle, которая называется его target.
ConstantBootstraps
Методы начальной загрузки для динамически вычисляемых констант.
ConstantCallSite
ConstantCallSite — это CallSite, целевой объект которого является постоянным и никогда не может быть изменён.
LambdaConversionException
LambdaConversionException
LambdaMetafactory
Методы, упрощающие создание простых «функциональных объектов», которые реализуют один или несколько интерфейсов, делегируя вызовы предоставленному MethodHandle, возможно, после адаптации типов и частичного вычисления аргументов.
MethodHandle
Дескриптор метода — это типизированная непосредственно исполняемая ссылка на базовый метод, конструктор, поле или аналогичную низкоуровневую операцию, с возможностью преобразования аргументов или возвращаемых значений.
MethodHandleInfo
Символическая ссылка, полученная путём разложения прямого дескриптора метода на составляющие его символические части.
MethodHandleProxies
Этот класс состоит исключительно из статических методов, помогающих адаптировать дескрипторы методов к другим типам JVM, например к интерфейсам.
MethodHandles
Этот класс состоит исключительно из статических методов, которые работают с дескрипторами методов или возвращают их.
MethodHandles.Lookup
Объект поиска — это фабрика для создания дескрипторов методов, если при создании требуется проверка доступа.
MethodHandles.Lookup.ClassOption
Набор параметров класса, определяющих, добавляется ли динамически скрытый класс, созданный методом Lookup::defineHiddenClass, в качестве нового члена к гнезду класса поиска и/или имеет ли скрытый класс сильную связь с загрузчиком классов, указанным как его определяющий загрузчик.
MethodType
Тип метода представляет аргументы и тип возвращаемого значения, принимаемые и возвращаемые дескриптором метода, либо аргументы и тип возвращаемого значения, передаваемые вызывающим кодом дескриптора метода и ожидаемые от него.
MutableCallSite
MutableCallSite — это CallSite, целевая переменная которого ведёт себя как обычное поле.
SerializedLambda
Сериализованная форма лямбда-выражения.
StringConcatException
StringConcatException выбрасывается классом StringConcatFactory при нарушении инвариантов связывания.
StringConcatFactory
Методы, упрощающие создание методов конкатенации строк, которые можно использовать для эффективного объединения известного количества аргументов известных типов, возможно, после адаптации типов и частичного вычисления аргументов.
SwitchPoint
SwitchPoint — это объект, который может сообщать о переходах состояния другим потокам.
TypeDescriptor
Сущность, имеющая дескриптор типа.
TypeDescriptor.OfField<F extends TypeDescriptor.OfField<F>>
Сущность, имеющая дескриптор типа поля.
TypeDescriptor.OfMethod<F extends TypeDescriptor.OfField<F>, M extends TypeDescriptor.OfMethod<F,M>>
Сущность, имеющая дескриптор типа метода. Дескрипторы методов, соответствующие разделу JVMS 4.3.3, могут быть представлены номинально с помощью MethodType::describeConstable; в противном случае их невозможно представить номинально.
VarHandle
VarHandle — это динамически строго типизированная ссылка на переменную или на параметрически определённое семейство переменных, включая статические поля, нестатические поля, элементы массивов или компоненты структуры данных вне кучи.
VarHandle.AccessMode
Набор режимов доступа, определяющих, как осуществляется доступ к переменной, на которую ссылается VarHandle.
VarHandle.VarHandleDesc
Номинальный дескриптор константы VarHandle.
VolatileCallSite
VolatileCallSite — это CallSite, целевой объект которого действует как volatile-переменная.
WrongMethodTypeException
Выбрасывается, чтобы указать, что код попытался вызвать дескриптор метода с неправильным типом метода.

Сообщить об ошибке или предложить улучшение
Дополнительные справочные материалы по API и документацию для разработчиков см. в разделе Документация Java SE, содержащем более подробные описания для разработчиков, обзоры концепций, определения терминов, обходные решения и примеры работающего кода. Другие версии.
Java является товарным знаком или зарегистрированным товарным знаком Oracle и/или её аффилированных лиц в США и других странах.
Авторское право © 1993, 2025, Oracle и/или её аффилированные лица, 500 Oracle Parkway, Redwood Shores, CA 94065 USA.
Все права защищены. Использование регулируется условиями лицензии и политикой распространения документации.

© 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/java.base/java/lang/invoke/package-summary.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API