Класс 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...). Альтернативная версия обобщает стандартную версию, предоставляя дополнительный контроль над поведением созданных функциональных объектов с помощью флагов и дополнительных аргументов. Альтернативная версия добавляет возможность управления следующими атрибутами функциональных объектов:
-
Несколько методов. Иногда полезно реализовать несколько вариантов сигнатуры метода, используя адаптацию аргументов или типов возврата. Это происходит, когда несколько различных сигнатур VM для метода логически считаются одним и тем же методом в языке. Флаг
FLAG_BRIDGESуказывает, что будет предоставлен список дополнительныхMethodTypes, каждый из которых будет реализован полученным функциональным объектом. Эти методы будут использовать одно и то же имя и экземплярный тип. -
Несколько интерфейсов. При необходимости функциональный объект может реализовывать более одного интерфейса. (Эти дополнительные интерфейсы обычно являются интерфейсами-маркерами без методов.) Флаг
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 равен null, или тип возврата Ra не равен null и адаптируется к 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.
Список аргументов этого метода включает три фиксированных параметра, соответствующих параметрам, автоматически помещаемым в стек JVM для метода-загрузчика при вызове 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.
Когда FLAG_SERIALIZABLE установлен в flags, функциональные объекты будут реализовывать Serializable, и будет иметь метод writeReplace, который возвращает соответствующий SerializedLambda. Класс caller должен иметь соответствующий метод $deserializeLambda$, как описано в SerializedLambda.
Когда цель CallSite возвращаемого этим методом вызывается, получающиеся функциональные объекты являются экземплярами класса со следующими свойствами:
- Класс реализует интерфейс, указанный в типе возвращаемого значения
factoryType, и любые интерфейсы, указанные вaltInterfaces - Класс объявляет методы с именем, заданным в
interfaceMethodName, и сигнатурой, заданной вinterfaceMethodType, и дополнительными сигнатурами, заданными вaltMethods - Класс может переопределять методы из
Object, и может реализовывать методы, связанные с сериализацией.
- Параметры:
-
caller- Представляет контекст поиска с привилегиями доступа вызывающего. В частности, контекст поиска должен иметь полный доступ к привилегиям. При использовании сinvokedynamic, это автоматически помещается в стек JVM. -
interfaceMethodName- Имя реализуемого метода. При использовании сinvokedynamic, это предоставляетсяNameAndTypeструктурыInvokeDynamicи автоматически помещается в стек JVM. -
factoryType- Ожидаемая подписьCallSite. Типы параметров представляют типы переменных захвата; тип возвращаемого значения - реализуемый интерфейс. При использовании сinvokedynamic, это предоставляетсяNameAndTypeструктурыInvokeDynamicи автоматически помещается в стек JVM. -
args- МассивObject, содержащий необходимые аргументыinterfaceMethodType,implementation,dynamicMethodType,flags, а также любые необязательные аргументы, как описано выше - Возвращает:
- CallSite, целевой объект которого может быть использован для захвата, генерирующего экземпляры интерфейса, названного
factoryType - Исключения:
-
LambdaConversionException- Еслиcallerне имеет полного доступа к привилегиям, или еслиinterfaceMethodNameне является допустимым именем JVM-метода, или если тип возвратаfactoryTypeне является интерфейсом, или если любой изaltInterfacesне является интерфейсом, или еслиimplementationне является прямым обработчиком метода, ссылающимся на метод или конструктор, или если нарушены связи, как определено вabove. -
NullPointerException- Если любой аргумент или любой компонентargsявляетсяnull. -
IllegalArgumentException- Если количество или типы компонентовargsне соответствуют вышеуказанным правилам, или еслиaltInterfaceCountилиaltMethodCountявляются отрицательными целыми числами. -
SecurityException- Если менеджер безопасности присутствует и он отказывается предоставить доступ отcallerк пакетуimplementation.
© 1993, 2021, 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/17/docs/api/java.base/java/lang/invoke/LambdaMetafactory.html