Spec-Zone.ru › OpenJDK 27

Класс LambdaMetafactory

java.lang.Object
java.lang.invoke.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.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 равен 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(MethodHandles.Lookup caller, String interfaceMethodName, MethodType factoryType, Object... args)
Упрощает создание простых «функциональных объектов», которые реализуют один или несколько интерфейсов посредством делегирования предоставленному MethodHandle после необходимой адаптации типов и частичного вычисления аргументов.
static CallSite metafactory(MethodHandles.Lookup caller, String interfaceMethodName, MethodType factoryType, MethodType interfaceMethodType, MethodHandle implementation, MethodType dynamicMethodType)
Упрощает создание простых «функциональных объектов», которые реализуют один или несколько интерфейсов посредством делегирования предоставленному MethodHandle после необходимой адаптации типов и частичного вычисления аргументов.

Методы, объявленные в классе Object

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

Подробное описание полей

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 являются отрицательными целыми числами.

Сообщить об ошибке или предложить улучшение
Для получения дополнительной справочной информации по API и документации для разработчиков см. документацию Java SE, содержащую более подробные описания для разработчиков, обзоры концепций, определения терминов, обходные решения и рабочие примеры кода. Другие версии.
Java является товарным знаком или зарегистрированным товарным знаком Oracle и/или ее аффилированных лиц в США и других странах.
Авторское право © 1993, 2026, Oracle и/или ее аффилированные лица, 500 Oracle Parkway, Redwood Shores, CA 94065 USA.
Все права защищены. Использование регулируется условиями лицензии и политикой распространения документации.

© 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.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API