Класс LambdaMetafactory
public final class LambdaMetafactory extends Object
Методы для облегчения создания простых «функциональных объектов», которые реализуют один или несколько интерфейсов путём делегирования предоставленному MethodHandle, возможно, после адаптации типов и частичной оценки аргументов. Эти методы обычно используются в качестве методов-bootstrap для invokedynamic мест вызова, для поддержки функций lambda-выражения и ссылка на метод в языке программирования 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указывает, что будет предоставлен список дополнительных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 в базовую обёртку(S); например Number для числовых типов |
| Ссылочный | Ссылочный | для типов параметров: S является супертипом Q для типов возвращаемых значений: нет | Преобразование из Q в S |
- Примечание API:
- Эти методы связывания предназначены для поддержки оценки лямбда-выражений и ссылок на методы в языке Java. Для каждого лямбда-выражения или ссылки на метод в исходном коде существует целевой тип, который является функциональным интерфейсом. Оценка лямбда-выражения приводит к созданию объекта его целевого типа. Рекомендуемый механизм для оценки лямбда-выражений заключается в преобразовании тела лямбда-выражения в метод, вызове вызова invokedynamic, у которого статический список аргументов описывает единственный метод функционального интерфейса и метод реализованного выражения, и возвращении объекта (объекта лямбда-выражения), который реализует целевой тип. (Для ссылок на методы реализующий метод — это просто указанный метод; преобразование не требуется.)
Список аргументов реализующего метода и список аргументов метода(ов) интерфейса могут отличаться несколькими способами. Реализующие методы могут иметь дополнительные аргументы для размещения аргументов, захваченных лямбда-выражением; также могут быть различия, возникающие из-за разрешенных адаптаций аргументов, таких как приведение типов, упаковка, распаковка и расширение примитивных типов. (Адаптации varargs не обрабатываются метафабриками; они должны обрабатываться вызывающей стороной.)
У вызовов invokedynamic есть два списка аргументов: статический и динамический. Статический список аргументов хранится в пуле констант; динамический аргумент помещается на стек операндов во время захвата. Метод инициализации имеет доступ ко всему статическому списку аргументов (в данном случае он содержит информацию об реализующем методе, целевом интерфейсе и методе(ах) целевого интерфейса), а также к сигнатуре метода, описывающей количество и статические типы (но не значения) динамических аргументов и статический возвращаемый тип вызова invokedynamic.
Реализующий метод описывается с помощью прямого хэндла метода, ссылающегося на метод или конструктор. Теоретически, можно использовать любой хэндл метода, но это не совместимо с некоторыми методами реализации и усложнит работу реализаций.
Использование, помимо оценки лямбда-выражений и ссылок на методы, не предполагается. Эти методы связывания могут изменять свои не указанные поведения в любое время, чтобы лучше соответствовать функциям языка Java, для поддержки которых они были разработаны, и такие изменения могут повлиять на непреднамеренное использование. Непреднамеренное использование этих методов связывания может привести к утечкам ресурсов или другим не определенным негативным последствиям.
- Примечание реализации:
- В эталонной реализации классы, реализующие созданные объекты функций, напрямую доступны из загрузчика классов вызывающей стороны, как классы и интерфейсы в исходном коде Java. Этот метод уменьшает использование памяти кучи, но в результате реализующие классы могут быть разгружены только в том случае, если вызывающий класс может быть разгружен. В частности, если вызывающий класс является слабым скрытым классом, реализующий класс, сильный скрытый класс, может не быть разгружен, даже если вызывающий класс может быть разгружен.
- С:
- 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.
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.
Когда флаг FLAG_SERIALIZABLE установлен в flags, функциональные объекты будут реализовывать 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:
- CallSite, целевой объект которого может использоваться для захвата, генерируя экземпляры интерфейса, указанного в
factoryType - Throws:
-
LambdaConversionException- Еслиcallerне имеет полного доступа, или еслиinterfaceMethodNameне является допустимым именем метода JVM, или если тип возвратаfactoryTypeне является интерфейсом, или если любой изaltInterfacesне является интерфейсом, или еслиimplementationне является прямым обработчиком метода, ссылающимся на метод или конструктор, или если нарушены инварианты связывания, как определено вabove. -
NullPointerException- Если какой-либо аргумент или компонентargsнекорректен. -
IllegalArgumentException- Если количество или типы компонентовargsне соответствуют вышеуказанным правилам, или еслиaltInterfaceCountилиaltMethodCountявляются отрицательными целыми числами.
© 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/java.base/java/lang/invoke/LambdaMetafactory.html