Класс 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 являются ссылочными типами, а 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), первый аргумент захвата (соответствующий получателю) должен быть не равен 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 есть два списка аргументов: список статических аргументов и список динамических аргументов. Список статических аргументов хранится в пуле констант; динамический аргумент помещается в стек операндов во время захвата. Метод начальной загрузки имеет доступ ко всему списку статических аргументов (который в данном случае содержит сведения о методе реализации, целевом интерфейсе и методах целевого интерфейса), а также к сигнатуре метода, описывающей количество и статические типы (но не значения) динамических аргументов и статический тип возвращаемого значения точки вызова 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 после необходимой адаптации типов и частичного вычисления аргументов. |
Методы, объявленные в классе Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait | Модификатор и тип | Метод | Описание |
|---|---|---|
protected Object |
clone() |
Создаёт и возвращает копию этого объекта. |
boolean |
equals |
Указывает, равен ли другой объект этому объекту. |
protected void |
finalize() |
Устарело, будет удалено: этот элемент API подлежит удалению в будущей версии. Финализация устарела и подлежит удалению в одном из будущих выпусков. |
final Class |
getClass() |
Возвращает класс времени выполнения этого Object. |
int |
hashCode() |
Возвращает хеш-код этого объекта. |
final void |
notify() |
Пробуждает один поток, ожидающий на мониторе этого объекта. |
final void |
notifyAll() |
Пробуждает все потоки, ожидающие на мониторе этого объекта. |
String |
toString() |
Возвращает строковое представление объекта. |
final void |
wait() |
Заставляет текущий поток ждать пробуждения, обычно в результате уведомления или прерывания. |
final void |
wait |
Заставляет текущий поток ждать пробуждения, обычно в результате уведомления или прерывания, либо до истечения определённого промежутка реального времени. |
final void |
wait |
Заставляет текущий поток ждать пробуждения, обычно в результате уведомления или прерывания, либо до истечения определённого промежутка реального времени. |
Подробное описание полей
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.