Класс LambdaMetafactory
public final class LambdaMetafactory extends Object
Методы, упрощающие создание простых «функциональных объектов», реализующих один или несколько интерфейсов посредством делегирования предоставленному MethodHandle, возможно, после адаптации типов и частичного вычисления аргументов. Обычно эти методы используются как методы начальной загрузки для точек вызова 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.Lookupcaller); подробности см. в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 - Типы Rt и Ru либо совпадают, либо оба являются ссылочными типами, причём Rt — подтип Ru
- K + N = M
- Для i=1..K: Di = Ai
- Для i=1..N тип Ti допускает адаптацию к Aj, где j=i+k
- Возвращаемый тип Rt является void либо возвращаемый тип Ra не является void и допускает адаптацию к Rt
Кроме того, во время захвата, если implementation соответствует методу экземпляра и имеются аргументы захвата (K > 0), первый аргумент захвата (соответствующий получателю) должен быть ненулевым.
Тип 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(MethodHandles.Lookup, String, MethodType, Object...), указывающий, что объект лямбда-выражения реализует интерфейсы помимо Serializable
|
static final int |
FLAG_SERIALIZABLE |
Флаг для altMetafactory(MethodHandles.Lookup, String, MethodType, Object...), указывающий, что объект лямбда-выражения должен быть сериализуемым |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
static CallSite |
altMetafactory |
Упрощает создание простых «функциональных объектов», реализующих один или несколько интерфейсов посредством делегирования предоставленному MethodHandle, после соответствующей адаптации типов и частичного вычисления аргументов. |
static CallSite |
metafactory |
Упрощает создание простых «функциональных объектов», реализующих один или несколько интерфейсов посредством делегирования предоставленному MethodHandle, после соответствующей адаптации типов и частичного вычисления аргументов. |
Подробное описание полей
FLAG_SERIALIZABLE
public static final int FLAG_SERIALIZABLE
altMetafactory(MethodHandles.Lookup, String, MethodType, Object...), указывающий, что объект лямбда-выражения должен быть сериализуемым- См. также:
FLAG_MARKERS
public static final int FLAG_MARKERS
altMetafactory(MethodHandles.Lookup, String, MethodType, 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.
Если в flags установлен FLAG_SERIALIZABLE, функциональные объекты будут реализовывать Serializable и иметь метод writeReplace, возвращающий соответствующий SerializedLambda. Класс caller должен иметь соответствующий метод $deserializeLambda$, как описано в SerializedLambda.
При вызове цели CallSite, возвращённой этим методом, создаваемые функциональные объекты являются экземплярами класса со следующими свойствами:
- Класс реализует интерфейс, указанный возвращаемым типом
factoryType, а также любые интерфейсы, указанные вaltInterfaces - Класс объявляет методы с именем, заданным
interfaceMethodName, и сигнатурой, заданнойinterfaceMethodType, а также с дополнительными сигнатурами, заданнымиaltMethods - Класс может переопределять методы из
Objectи реализовывать методы, связанные с сериализацией.
- Параметры:
-
caller— представляет контекст поиска с правами доступа вызывающего кода. В частности, контекст поиска должен обладать полным доступом с привилегиями. При использовании сinvokedynamicвиртуальная машина автоматически помещает этот параметр в стек. -
interfaceMethodName— имя реализуемого метода. При использовании сinvokedynamicоно предоставляетсяNameAndTypeструктурыInvokeDynamicи автоматически помещается в стек виртуальной машиной. -
factoryType— ожидаемая сигнатураCallSite. Типы параметров представляют типы захватываемых переменных; возвращаемый тип — реализуемый интерфейс. При использовании сinvokedynamicона предоставляетсяNameAndTypeструктурыInvokeDynamicи автоматически помещается в стек виртуальной машиной. -
args— массивObject, содержащий требуемые аргументыinterfaceMethodType,implementation,dynamicMethodType,flagsи любые необязательные аргументы, как описано выше - Возвращает:
- CallSite, цель которого можно использовать для захвата, создавая экземпляры интерфейса, указанного в
factoryType - Вызывает исключения:
-
LambdaConversionException— еслиcallerне обладает полным доступом с привилегиями, еслиinterfaceMethodNameне является допустимым именем метода JVM, если возвращаемый типfactoryTypeне является интерфейсом, если какой-либо изaltInterfacesне является интерфейсом, еслиimplementationне является прямым дескриптором метода, ссылающимся на метод или конструктор, или если нарушены инварианты связывания, определённые вabove. -
NullPointerException— если какой-либо аргумент или компонентargsравенnull. -
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://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/invoke/LambdaMetafactory.html