Пакет java.lang.invoke
Пакет java.lang.invoke содержит поддержку динамических языков, предоставляемую напрямую ядром Java-библиотек и виртуальной машиной.
См.: Описание
| Интерфейс | Описание |
|---|---|
| MethodHandleInfo | Символьная ссылка, полученная путем разбиения прямого обработчика метода на его составляющие символьные части. |
| Класс | Описание |
|---|---|
| CallSite |
|
| ConstantCallSite |
|
| LambdaMetafactory | Методы для облегчения создания простых «функциональных объектов», реализующих один или несколько интерфейсов путём делегирования предоставленному |
| MethodHandle | Обработчик метода — это типизированная, непосредственно исполняемая ссылка на базовый метод, конструктор, поле или аналогичную низкоуровневую операцию с необязательными преобразованиями аргументов или возвращаемых значений. |
| MethodHandleProxies | Этот класс состоит исключительно из статических методов, которые помогают адаптировать обработчики методов к другим типам JVM, таким как интерфейсы. |
| MethodHandles | Этот класс состоит исключительно из статических методов, которые работают с обработчиками методов или возвращают их. |
| MethodHandles.Lookup | Объект поиска — это фабрика для создания обработчиков методов, когда для создания требуется проверка доступа. |
| MethodType | Тип метода представляет аргументы и возвращаемый тип, принимаемые и возвращаемые обработчиком метода, или аргументы и возвращаемый тип, переданные и ожидаемые вызывающим обработчиком метода. |
| MutableCallSite |
|
| SerializedLambda | Сериализованная форма лямбда-выражения. |
| SwitchPoint |
|
| VolatileCallSite |
|
| Исключение | Описание |
|---|---|
| LambdaConversionException | LambdaConversionException |
| WrongMethodTypeException | Выбрасывается, чтобы указать, что код попытался вызвать обработчик метода с неправильным типом метода. |
Описание пакета java.lang.invoke
Пакет java.lang.invoke содержит поддержку динамических языков, предоставляемую непосредственно ядром Java и виртуальной машиной.
Как описано в спецификации Java Virtual Machine, некоторые типы в этом пакете имеют особые отношения к поддержке динамических языков в виртуальной машине:
- Класс
MethodHandleсодержит методы с полиморфизмом сигнатур, которые могут быть связаны независимо от их описателя типа. Обычно для связи методов требуется точное соответствие описателей типов. - Формат байткода JVM поддерживает непосредственные константы классов
MethodHandleиMethodType.
Обзор изменений в Java Virtual Machine
Следующая информация низкого уровня обобщает соответствующие части спецификации Java Virtual Machine. Для получения полной информации, пожалуйста, обратитесь к текущей версии этой спецификации. Каждая встречающаяся инструкцияinvokedynamic называется сайтом динамического вызова. Инструкции invokedynamic
Сайт динамического вызова первоначально находится в несвязанном состоянии. В этом состоянии нет целевого метода для вызова сайтом. Прежде чем JVM сможет выполнить сайт динамического вызова (инструкцию invokedynamic), сайт должен быть связан. Связывание выполняется путем вызова bootstrap-метода, которому предоставляется статическая информация о сайте вызова, и который должен создать method handle, определяющий поведение сайта вызова.
Каждая инструкция invokedynamic статически указывает свой собственный bootstrap-метод как ссылку на пул констант. Ссылка на пул констант также определяет имя сайта вызова и описатель типа, подобно инструкциям invokevirtual и другим инструкциям вызова.
Связывание начинается с разрешения записи в пуле констант для bootstrap-метода и разрешения объекта MethodType для описателя типа сайта динамического вызова. Этот процесс разрешения может инициировать загрузку класса. Поэтому он может вызвать ошибку, если класс не удается загрузить. Эта ошибка становится аномальным завершением выполнения сайта динамического вызова. Связывание не инициирует инициализацию класса.
Bootstrap-метод вызывается по меньшей мере с тремя значениями:
MethodHandles.Lookup, объект поиска в классе вызывающего метода, в котором происходит сайт динамического вызоваString, имя метода, упомянутого в сайте вызоваMethodType, разрешенный описатель типа вызова- необязательно, от 1 до 251 дополнительного статического аргумента, взятого из пула констант
MethodHandle.invoke. Возвращаемое значение должно быть CallSite (или подклассом). Тип целевого сайта вызова должен быть точно равен типу, полученному из описателя типа сайта динамического вызова и переданному в bootstrap-метод. Сайт вызова затем становится постоянно связанным с сайтом динамического вызова. Как документировано в спецификации JVM, все ошибки, возникающие при связывании сайта динамического вызова, сообщаются BootstrapMethodError, который выбрасывается как аномальное завершение выполнения сайта динамического вызова. Если это произойдет, та же ошибка будет выброшена для всех последующих попыток выполнить сайт динамического вызова.
Время связывания
Сайт динамического вызова связывается непосредственно перед его первым выполнением. Вызов bootstrap-метода, реализующего связывание, происходит в потоке, который пытается выполнить его впервые.Если таких потоков несколько, bootstrap-метод может быть вызван в нескольких потоках одновременно. Поэтому bootstrap-методы, которые обращаются к глобальным данным приложения, должны принимать обычные меры предосторожности против гонок. В любом случае, каждая инструкция invokedynamic либо не связана, либо связана с уникальным объектом CallSite.
В приложении, которому требуются сайты динамического вызова с индивидуально изменяемым поведением, их bootstrap-методы должны создавать отдельные объекты CallSite – один для каждого запроса связывания. В качестве альтернативы приложение может связать один объект CallSite с несколькими инструкциями invokedynamic, в этом случае изменение целевого метода станет видимым в каждой из инструкций.
Если несколько потоков одновременно выполняют bootstrap-метод для одного сайта динамического вызова, JVM должна выбрать один объект CallSite и установить его видимым для всех потоков. Все остальные вызовы bootstrap-методов разрешается завершить, но их результаты игнорируются, а вызовы сайтов динамических вызовов продолжаются с первоначально выбранным целевым объектом.
Обсуждение: Эти правила не позволяют JVM дублировать сайты динамических вызовов или выполнять вызовы bootstrap-методов «без причины». Каждый сайт динамического вызова переходит не более чем один раз из несвязанного в связанное состояние непосредственно перед своим первым вызовом. Нет способа отменить действие завершенного вызова bootstrap-метода.
Типы bootstrap-методов
До тех пор, пока каждый bootstrap-метод может быть правильно вызванMethodHandle.invoke, его подробный тип произволен. Например, первым аргументом мог быть Object вместо MethodHandles.Lookup, а тип возвращаемого значения мог быть также Object вместо CallSite. (Обратите внимание, что типы и количество стековых аргументов ограничивают допустимые типы bootstrap-методов соответствующим образом типизированными статическими методами и конструкторами подклассов CallSite.) Если данная инструкция invokedynamic не указывает статических аргументов, bootstrap-метод инструкции будет вызван с тремя аргументами, передающими класс вызывающего метода, имя и тип метода. Если инструкция invokedynamic указывает один или несколько статических аргументов, эти значения будут переданы как дополнительные аргументы в метод-обработчик. (Обратите внимание, что поскольку существует ограничение в 255 аргументов для любого метода, не более 251 дополнительного аргумента могут быть предоставлены, так как сам bootstrap-метод-обработчик и его первые три аргумента также должны быть помещены в стек.) Bootstrap-метод будет вызван как будто с помощью MethodHandle.invoke или invokeWithArguments. (Отличить их невозможно.)
Нормальные правила преобразования аргументов для MethodHandle.invoke применяются ко всем стековым аргументам. Например, если помещенное значение является примитивным типом, оно может быть преобразовано в ссылку с помощью преобразования «упаковки». Если bootstrap-метод является методом с переменным числом аргументов (бит модификатора 0x0080 установлен), то некоторые или все указанные здесь аргументы могут быть собраны в параметр массива следования. (Это не специальное правило, а скорее полезное следствие взаимодействия между константами CONSTANT_MethodHandle, битом модификатора для методов с переменным числом аргументов и преобразованием asVarargsCollector.)
С учетом этих правил, вот примеры допустимых объявлений bootstrap-методов, заданных различным количеством N дополнительных аргументов. Первые строки (отмеченные *) будут работать для любого количества дополнительных аргументов.
| N | Пример bootstrap-метода |
|---|---|
| * | 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) |
| 0 | 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) |
| 2 | CallSite bootstrap(Lookup caller, String name, MethodType type, String... args) |
| 2 | CallSite bootstrap(Lookup caller, String name, MethodType type, String x, int y) |
CONSTANT_String и CONSTANT_Integer соответственно. Предварительный к последнему пример предполагает, что все дополнительные аргументы имеют тип CONSTANT_String. Другие примеры работают со всеми типами дополнительных аргументов. Как отмечалось выше, фактический тип метода bootstrap-метода может варьироваться. Например, четвертым аргументом может быть MethodHandle, если это тип соответствующей константы в записи CONSTANT_InvokeDynamic. В этом случае вызов MethodHandle.invoke передаст дополнительную константу обработчика метода как Object, но механизм соответствия типов MethodHandle.invoke преобразует ссылку обратно в MethodHandle перед вызовом bootstrap-метода. (Если вместо этого была передана строковая константа, из-за плохо сгенерированного кода, это преобразование затем потерпит неудачу, что приведет к BootstrapMethodError.)
Обратите внимание, что в результате вышеуказанных правил bootstrap-метод может принять примитивный аргумент, если он может быть представлен записью в пуле констант. Однако аргументы типа boolean, byte, short или char не могут быть созданы для bootstrap-методов, так как такие константы не могут быть представлены напрямую в пуле констант, и вызов bootstrap-метода не выполнит необходимые преобразования сужения примитивных типов.
Дополнительные аргументы bootstrap-метода предназначены для того, чтобы разработчики языков могли безопасно и компактно кодировать метаданные. В принципе, имя и дополнительные аргументы избыточны, так как каждому сайту вызова можно было бы предоставить собственный уникальный bootstrap-метод. Такая практика, вероятно, приведет к большим файлам классов и пулам констант.
- С:
- 1.7
© 1993, 2020, 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.