Класс LambdaMetafactory
public final class LambdaMetafactory extends Object
Методы для облегчения создания простых «функциональных объектов», реализующих один или несколько интерфейсов путём делегирования предоставленному MethodHandle, возможно после адаптации типов и частичной оценки аргументов. Эти методы обычно используются в качестве методов-bootstrap для invokedynamic мест вызова, для поддержки функций лямбда-выражений и ссылок на методы в языке программирования Java.
Непрямой доступ к поведению, заданному предоставленным MethodHandle, происходит поэтапно через три фазы:
-
Связывание происходит при вызове методов в этом классе. Они принимают в качестве аргументов интерфейс, который должен быть реализован (обычно функциональный интерфейс, имеющий единственный абстрактный метод), имя и сигнатуру метода из этого интерфейса, который нужно реализовать, прямой обработчик методов описывающий желаемое поведенческое реализацию для этого метода, и, возможно, другую дополнительную метаданные, и создают
CallSite, цель которого можно использовать для создания подходящих функциональных объектов.Связывание может включать динамическую загрузку нового класса, который реализует целевой интерфейс, или повторное использование подходящего существующего класса.
CallSiteможно рассматривать как «фабрику» для функциональных объектов, поэтому эти методы связывания называются «метафабриками». -
Захват происходит, когда цель
CallSiteвызывается, как правило, черезinvokedynamicместо вызова, создавая функциональный объект. Это может произойти много раз для одной фабрикиCallSite.Если поведение
MethodHandleимеет дополнительные параметры, помимо параметров метода указанного интерфейса, эти параметры называются захваченными параметрами, которые необходимо предоставить в качестве аргументов целевомуCallSite. Ожидаемое количество и типы захваченных параметров определяются во время связывания.Захват может включать выделение нового функционального объекта или возврат подходящего существующего функционального объекта. Идентификатор созданного объектом захвата непредсказуем, поэтому операции, чувствительные к идентификатору (такие как равенство ссылок, блокировка объектов и
System.identityHashCode()), могут давать разные результаты в разных реализациях или даже при разных вызовах в одной и той же реализации. Вызов происходит, когда вызывается реализованный метод интерфейса для функционального объекта. Это может произойти много раз для одного функционального объекта. Метод, на который ссылается реализация
MethodHandleвызывается, передавая ему захваченные и входные аргументы. Результат метода возвращается.
Иногда полезно ограничивать набор входных данных или результатов, разрешенных при вызове. Например, когда общий интерфейс Predicate<T> параметризован как Predicate<String>, вход должен быть String, даже если реализуемый метод допускает любые Object. В момент связывания дополнительный параметр MethodType описывает «динамический» тип метода; при вызове аргументы и возможный результат проверяются по этому MethodType.
Этот класс предоставляет два типа методов связывания: стандартную версию (metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType)) с оптимизированным протоколом и альтернативную версию altMetafactory(MethodHandles.Lookup, String, MethodType, Object...). Альтернативная версия является обобщением стандартной версии, предоставляя дополнительный контроль над поведением сгенерированных функциональных объектов через флаги и дополнительные аргументы. Альтернативная версия добавляет возможность управления следующими атрибутами функциональных объектов:
-
Несколько методов. Иногда полезно реализовать несколько вариантов подписи метода, связанных с адаптацией аргументов или типов возвращаемых значений. Это происходит, когда несколько различных виртуальных машин (ВМ) сигнатуры для метода логически считаются одним и тем же методом в языке. Флаг
FLAG_BRIDGESуказывает, что будет предоставлен список дополнительныхMethodType, каждый из которых будет реализован созданным функциональным объектом. Эти методы будут иметь одинаковое имя и тип экземпляра. -
Несколько интерфейсов. При необходимости, функциональный объект может реализовывать более одного интерфейса. (Эти дополнительные интерфейсы, как правило, маркерные интерфейсы без методов.) Флаг
FLAG_MARKERSуказывает, что будет предоставлен список дополнительных интерфейсов, каждый из которых должен быть реализован созданным функциональным объектом. -
Сериализация. Сгенерированные функциональные объекты, как правило, не поддерживают сериализацию. Если нужно,
FLAG_SERIALIZABLEможет быть использован для указания того, что функциональные объекты должны быть сериализуемыми. Сериализуемые функциональные объекты будут использовать, как свою сериализованную форму, экземпляры классаSerializedLambda, что требует дополнительной помощи от класса захвата (класса, описанного параметромMethodHandles.Lookupпараметрcaller); см.SerializedLambdaдля получения подробностей.
Предположим, что аргументы связывания следующие:
-
factoryType(описывающийCallSiteсигнатуру) имеет K параметров типов (D1..Dk) и тип возвращаемого значения Rd; -
interfaceMethodType(описывающий тип реализуемого метода) имеет N параметров типов (U1..Un) и тип возвращаемого значения Ru; -
implementation(MethodHandleпредоставляющий реализацию) имеет M параметров типов (A1..Am) и тип возвращаемого значения Ra (если метод описывает метод экземпляра, тип метода этого обработчика методов уже включает дополнительный первый аргумент, соответствующий получателю); -
dynamicMethodType(разрешающий ограничения на вызов) имеет N параметров типов (T1..Tn) и тип возвращаемого значения Rt.
Тогда следующие инварианты связывания должны выполняться:
-
interfaceMethodTypeиdynamicMethodTypeимеют одинаковую арность N, а для i=1..N, Ti и Ui - одинаковый тип, или Ti и Ui - оба ссылочные типы, и Ti является подтипом Ui - Либо Rt и Ru - один и тот же тип, либо оба являются ссылочными типами и Rt является подтипом Ru
- K + N = M
- Для i=1..K, Di = Ai
- Для i=1..N, Ti может быть адаптирован к Aj, где j=i+k
- Тип возврата Rt - пустой, или тип возврата Ra не пустой и может быть адаптирован к Rt
Кроме того, во время захвата, если implementation соответствует методу экземпляра, и есть какие-либо аргументы захвата (K > 0), то первый аргумент захвата (соответствующий получателю) должен быть не null.
Тип Q считается приводимым к типу S следующим образом:
| Q | S | Проверки на этапе связывания | Проверки на этапе вызова |
|---|---|---|---|
| Примитивный | Примитивный | Q может быть преобразован в S с помощью расширяющего примитивного преобразования | Нет |
| Примитивный | Ссылочный | S является супертипом Wrapper(Q) | Преобразование из Wrapper(Q) в S |
| Ссылочный | Примитивный | для типов параметров: Q является обёрткой над примитивным типом и Primitive(Q) может быть расширено до S для типов возврата: Если Q является обёрткой над примитивным типом, проверяется, что Primitive(Q) может быть расширено до S | Если Q не является обёрткой над примитивным типом, Q преобразуется в базовую обёртку Wrapper(S); например, Number для числовых типов |
| Ссылочный | Ссылочный | для типов параметров: S является супертипом Q для типов возврата: нет | Преобразование из Q в S |
- Примечание API:
- Эти методы связывания разработаны для поддержки оценки лямбда-выражений и ссылок на методы в языке Java. Для каждого лямбда-выражения или ссылки на метод в исходном коде существует целевой тип, который является функциональным интерфейсом. Оценка лямбда-выражения приводит к объекту его целевого типа. Рекомендуемый механизм для оценки лямбда-выражений заключается в разборе тела лямбда-выражения в метод, вызове динамического места вызова invokedynamic, чья статическая аргументная запись описывает единственный метод функционального интерфейса и дезагрированный метод реализации, и возвращает объект (объект лямбды), который реализует целевой тип. (Для ссылок на методы метод реализации — это просто метод-ссылка, разбор не требуется.)
Список аргументов метода реализации и список аргументов метода(ов) интерфейса могут отличаться по нескольким причинам. Методы реализации могут иметь дополнительные аргументы для учета аргументов, захваченных лямбда-выражением; могут также существовать различия, возникающие в результате разрешенных адаптаций аргументов, таких как преобразование, бокс, унбокс и расширение примитивных типов. (Адаптации varargs не обрабатываются метафабриками; они должны обрабатываться вызывающим методом.)
У мест вызова invokedynamic есть два списка аргументов: статический и динамический. Статический список аргументов хранится в пуле констант; динамический аргумент помещается в стек операндов во время захвата. Метод bootstrap имеет доступ ко всему статическому списку аргументов (который в данном случае включает информацию о методе реализации, целевом интерфейсе и целевом методе(ах) интерфейса), а также к подписи метода, описывающей количество и статические типы (но не значения) динамических аргументов и статический тип возврата места вызова invokedynamic.
Метод реализации описывается прямым обработчиком методов, ссылающимся на метод или конструктор. Теоретически, можно использовать любой обработчик методов, но это несовместимо с некоторыми методами реализации и усложнит работу реализаций.
- С:
- 1.8
Краткое описание полей
| Модификатор и тип | Поле | Описание |
|---|---|---|
static final int |
FLAG_BRIDGES |
Флаг для альтернативных метафабрик, указывающий, что объект лямбда-выражения требует дополнительных методов, вызывающих implementation
|
static final int |
FLAG_MARKERS |
Флаг для altMetafactory(java.lang.invoke.MethodHandles.Lookup, java.lang.String, java.lang.invoke.MethodType, java.lang.Object...), указывающий, что объект лямбда-выражения реализует другие интерфейсы помимо Serializable
|
static final int |
FLAG_SERIALIZABLE |
Флаг для altMetafactory(java.lang.invoke.MethodHandles.Lookup, java.lang.String, java.lang.invoke.MethodType, java.lang.Object...), указывающий, что объект лямбда-выражения должен быть сериализуемым |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
static CallSite |
altMetafactory |
Обеспечивает создание простых "функциональных объектов", которые реализуют один или несколько интерфейсов путём делегирования предоставленному MethodHandle, после соответствующей адаптации типов и частичной оценки аргументов. |
static CallSite |
metafactory |
Обеспечивает создание простых "функциональных объектов", которые реализуют один или несколько интерфейсов путём делегирования предоставленному MethodHandle, после соответствующей адаптации типов и частичной оценки аргументов. |
Подробное описание полей
FLAG_SERIALIZABLE
public static final int FLAG_SERIALIZABLE
altMetafactory(java.lang.invoke.MethodHandles.Lookup, java.lang.String, java.lang.invoke.MethodType, java.lang.Object...), указывающий, что объект лямбда-выражения должен быть сериализуемым- См. также:
FLAG_MARKERS
public static final int FLAG_MARKERS
altMetafactory(java.lang.invoke.MethodHandles.Lookup, java.lang.String, java.lang.invoke.MethodType, java.lang.Object...), указывающий, что объект лямбда-выражения реализует другие интерфейсы помимо Serializable
- См. также:
FLAG_BRIDGES
public static final int FLAG_BRIDGES
implementation
- См. также:
Подробное описание методов
metafactory
public static CallSite metafactory(MethodHandles.Lookup caller, String interfaceMethodName, MethodType factoryType, MethodType interfaceMethodType, MethodHandle implementation, MethodType dynamicMethodType) throws LambdaConversionException
MethodHandle, после соответствующей адаптации типов и частичной оценки аргументов. Обычно используется в качестве метода-загрузчика для invokedynamic вызовов, для поддержки лямбда-выражений и ссылок на методы в языке программирования Java. Это стандартная, оптимизированная метафабрика; дополнительные возможности предоставляет altMetafactory(MethodHandles.Lookup, String, MethodType, Object...). Общее описание поведения этого метода представлено в above.
При вызове целевого объекта CallSite , возвращаемого этим методом, получаемые функциональные объекты являются экземплярами класса, реализующего интерфейс, указанный типом возврата factoryType, объявляющего метод с именем, заданным interfaceMethodName, и сигнатурой, заданной interfaceMethodType. Он также может переопределять дополнительные методы из Object.
- Параметры:
-
caller- Представляет контекст поиска с правами доступа вызывающего объекта. В частности, контекст поиска должен иметь полные права доступа. При использовании сinvokedynamic, это автоматически добавляется в стек виртуальной машины. -
interfaceMethodName- Имя реализуемого метода. При использовании сinvokedynamic, это предоставляетсяNameAndTypeструктурыInvokeDynamicи автоматически добавляется в стек виртуальной машины. -
factoryType- Ожидаемая сигнатураCallSite. Типы параметров представляют типы переменных захвата; тип возврата — реализуемый интерфейс. При использовании сinvokedynamic, это предоставляетсяNameAndTypeструктурыInvokeDynamicи автоматически добавляется в стек виртуальной машины. -
interfaceMethodType- Подпись и тип возвращаемого значения реализуемого метода функциональным объектом. -
implementation- Прямой метод-обработчик, описывающий реализуемый метод, который должен вызываться (с соответствующей адаптацией типов аргументов и типов возвращаемого значения, и с предварительно добавленными в вызов аргументами захваченных аргументов) во время вызова. -
dynamicMethodType- Подпись и тип возвращаемого значения, которые должны быть динамически применены во время вызова. В простых случаях это то же, что иinterfaceMethodType. - Возвращает:
- объект CallSite, цель которого может быть использована для захвата, генерируя экземпляры интерфейса, указанного типом возврата
factoryType - Исключения:
-
LambdaConversionException- Еслиcallerне имеет полных прав доступа, или еслиinterfaceMethodNameне является допустимым именем метода JVM, или если тип возвратаfactoryTypeне является интерфейсом, или еслиimplementationне является прямым методом-обработчиком, ссылающимся на метод или конструктор, или если нарушены связи, как определено вabove. -
NullPointerException- Если какой-либо аргументnull. -
SecurityException- Если присутствует менеджер безопасности и он отклоняет доступ отcallerк пакетуimplementation.
altMetafactory
public static CallSite altMetafactory(MethodHandles.Lookup caller, String interfaceMethodName, MethodType factoryType, Object... args) throws LambdaConversionException
MethodHandle после соответствующего преобразования типов и частичной оценки аргументов. Обычно используется в качестве метода-загрузчика для invokedynamic мест вызова, для поддержки функций выражений лямбда и ссылок на методы в языке программирования Java. Это общий, более гибкий метафабрикатор; упрощенная версия предоставляется metafactory(java.lang.invoke.MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType). Общее описание поведения этого метода приведено в above.
Список аргументов для этого метода включает три фиксированных параметра, соответствующих параметрам, автоматически помещенным в стек ВМ для метода-загрузчика при вызове invokedynamic, и параметр Object[], содержащий дополнительные параметры. Объявленный список аргументов для этого метода:
CallSite altMetafactory(MethodHandles.Lookup caller,
String interfaceMethodName,
MethodType factoryType,
Object... args)
но он ведет себя так, как будто список аргументов имеет следующий вид:
CallSite altMetafactory(MethodHandles.Lookup caller,
String interfaceMethodName,
MethodType factoryType,
MethodType interfaceMethodType,
MethodHandle implementation,
MethodType dynamicMethodType,
int flags,
int altInterfaceCount, // IF flags has MARKERS set
Class... altInterfaces, // IF flags has MARKERS set
int altMethodCount, // IF flags has BRIDGES set
MethodType... altMethods // IF flags has BRIDGES set
)
Аргументы, которые появляются в списке аргументов для metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType), имеют ту же спецификацию, что и в этом методе. Дополнительные аргументы интерпретируются следующим образом:
-
flagsуказывает дополнительные параметры; это побитовое ИЛИ желаемых флагов. Определенные флаги:FLAG_BRIDGES,FLAG_MARKERSиFLAG_SERIALIZABLE. -
altInterfaceCount— количество дополнительных интерфейсов, которые должен реализовать функциональный объект, и присутствует только в том случае, если установлен флагFLAG_MARKERS. -
altInterfaces— список дополнительных интерфейсов для реализации, длина которого равнаaltInterfaceCount, и присутствует только в том случае, если установлен флагFLAG_MARKERS. -
altMethodCount— количество дополнительных сигнатур методов, которые должен реализовать функциональный объект, и присутствует только в том случае, если установлен флагFLAG_BRIDGES. -
altMethods— список дополнительных сигнатур методов для реализации, длина которого равнаaltMethodCount, и присутствует только в том случае, если установлен флагFLAG_BRIDGES.
Каждый класс, указанный в altInterfaces, подчиняется тем же ограничениям, что и Rd, тип возвращаемого значения factoryType, как описано в above. Каждый MethodType класс, указанный в altMethods, подчиняется тем же ограничениям, что и interfaceMethodType, как описано в above.
Когда в flags установлен флаг FLAG_SERIALIZABLE, функциональные объекты будут реализовывать Serializable, и будут иметь метод writeReplace, который возвращает соответствующий SerializedLambda. Класс caller должен иметь соответствующий метод $deserializeLambda$, как описано в SerializedLambda.
Когда целевой объект CallSite возвращаемый этим методом, вызывается, результирующие функциональные объекты являются экземплярами класса со следующими свойствами:
- Класс реализует интерфейс, указанный типом возвращаемого значения
factoryTypeи любыми интерфейсами, указанными вaltInterfaces - Класс объявляет методы с именем, заданным в
interfaceMethodName, и сигнатурой, заданной вinterfaceMethodType, и дополнительными сигнатурами, заданными вaltMethods - Класс может переопределять методы из
Object, и может реализовывать методы, связанные с сериализацией.
- Parameters:
-
caller- Представляет контекст поиска с привилегиями доступа вызывающего. В частности, контекст поиска должен иметь полный доступ. При использовании сinvokedynamic, это автоматически добавляется в стек ВМ. -
interfaceMethodName- Имя метода для реализации. При использовании сinvokedynamic, это предоставляетсяNameAndTypeструктурыInvokeDynamicи автоматически добавляется в стек ВМ. -
factoryType- Ожидаемая сигнатураCallSite. Типы параметров представляют типы переменных захвата; тип возвращаемого значения — интерфейс для реализации. При использовании сinvokedynamic, это предоставляетсяNameAndTypeструктурыInvokeDynamicи автоматически добавляется в стек ВМ. -
args- МассивObjectсодержащий необходимые аргументыinterfaceMethodType,implementation,dynamicMethodType,flags, и любые необязательные аргументы, как описано выше - Returns:
- a CallSite, целевой объект которого может использоваться для захвата, генерируя экземпляры интерфейса, указанного в
factoryType - Throws:
-
LambdaConversionException- Еслиcallerне имеет полного доступа, илиinterfaceMethodNameне является допустимым именем метода JVM, или тип возвращаемого значенияfactoryTypeне является интерфейсом, или любой изaltInterfacesне является интерфейсом, илиimplementationне является прямым обращением к методу или конструктору, или нарушены ограничения связывания, как определеноabove. -
NullPointerException- Если любой аргумент или любой компонентargsявляетсяnull. -
IllegalArgumentException- Если количество или типы компонентовargsне соответствуют вышеуказанным правилам, илиaltInterfaceCountилиaltMethodCountявляются отрицательными числами. -
SecurityException- Если присутствует менеджер безопасности, и он отказывает в доступе отcallerк пакетуimplementation.
© 1993, 2023, 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/21/docs/api/java.base/java/lang/invoke/LambdaMetafactory.html