Spec-Zone.ru › OpenJDK 25

Класс 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
  • Типы 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(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

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

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, 2025, 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.
https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/invoke/LambdaMetafactory.html

Spec-Zone.ru

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