Класс LambdaMetafactory

public final class LambdaMetafactory
extends Object

Методы для облегчения создания простых «функциональных объектов», которые реализуют один или несколько интерфейсов путём делегирования предоставленному MethodHandle, возможно, после адаптации типов и частичной оценки аргументов. Эти методы обычно используются в качестве методов-загрузчиков для invokedynamic мест вызова, чтобы поддерживать возможности лямбда-выражения и ссылок на методы в языке программирования Java.

Непрямой доступ к поведению, указанному в предоставленном MethodHandle, происходит последовательно через три фазы:

  • Связывание происходит при вызове методов в этом классе. Они принимают в качестве аргументов интерфейс, который должен быть реализован (обычно функциональный интерфейс, с одним абстрактным методом), имя и сигнатуру метода из этого интерфейса, который должен быть реализован, дескриптор метода, описывающий желаемое поведение реализации для этого метода, и, возможно, другую дополнительную метаданные, и производят CallSite, целевой объект которого может быть использован для создания соответствующих функциональных объектов. Связывание может включать динамическую загрузку нового класса, реализующего целевой интерфейс. CallSite можно рассматривать как «фабрику» для функциональных объектов, поэтому эти методы связывания называются «метафабриками».
  • Получение происходит, когда целевой объект CallSite вызывается, обычно через invokedynamic место вызова, создавая функциональный объект. Это может происходить многократно для одной фабрики CallSite. Получение может включать выделение нового функционального объекта или возвращение существующего функционального объекта. Поведение MethodHandle может иметь дополнительные параметры помимо параметров указанного метода интерфейса; они называются захваченными параметрами, которые должны быть предоставлены в качестве аргументов целевому объекту CallSite, и которые могут быть связаны с поведением MethodHandle на ранней стадии. Количество захваченных параметров и их типы определяются во время связывания. Идентификатор функционального объекта, созданного путём вызова целевого объекта CallSite, непредсказуем, поэтому операции, чувствительные к идентификатору (такие как равенство ссылок, блокировка объектов и System.identityHashCode() могут давать разные результаты в разных реализациях или даже при разных вызовах в одной и той же реализации.
  • Вызов происходит, когда реализованный метод интерфейса вызывается на функциональном объекте. Это может происходить многократно для одного функционального объекта. Метод, на который ссылается поведение MethodHandle, вызывается с захваченными аргументами и любыми дополнительными аргументами, предоставленными при вызове, как если бы это было сделано с помощью MethodHandle.invoke(Object...).

Иногда полезно ограничивать набор входных данных или результатов, разрешённых при вызове. Например, когда обобщённый интерфейс 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 для получения подробностей.

Предположим, что аргументы связывания следующие:

  • invokedType (описывающий сигнатуру CallSite ) имеет K параметров типов (D1..Dk) и тип возвращаемого значения Rd;
  • samMethodType (описывающий тип реализованного метода) имеет N параметров типов (U1..Un) и тип возвращаемого значения Ru;
  • implMethod (метод MethodHandle, обеспечивающий реализацию, имеет M параметров типов (A1..Am) и тип возвращаемого значения Ra (если метод описывает метод экземпляра, тип метода этого дескриптора метода уже включает дополнительный первый аргумент, соответствующий получателю);
  • instantiatedMethodType (разрешающий ограничения при вызове) имеет N параметров типов (T1..Tn) и тип возвращаемого значения Rt.

Тогда должны выполняться следующие инварианты связывания:

  • Rd является интерфейсом
  • implMethod является прямым дескриптором метода
  • samMethodType и instantiatedMethodType имеют одинаковую арность 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

Кроме того, на этапе захвата, если implMethod соответствует методу экземпляра и есть какие-либо аргументы захвата (K > 0 ), то первый аргумент захвата (соответствующий получателю) должен быть не нулевым.

Тип 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.

Примечание реализации:
Метод реализации описывается дескриптором метода. Теоретически может использоваться любой дескриптор метода. В настоящее время поддерживаются прямые дескрипторы методов, представляющие вызов виртуальных, интерфейсных, конструкторов и статических методов.
С:
1.8

Поля

Модификатор и тип Поле Описание
static int FLAG_BRIDGES

Флаг для альтернативных метафабрик, указывающий, что объекту лямбда-выражения требуются дополнительные мостовые методы

static int FLAG_MARKERS

Флаг для альтернативных метафабрик, указывающий, что объект лямбда-выражения реализует другие интерфейсы-маркеры помимо Serializable

static int FLAG_SERIALIZABLE

Флаг для альтернативных метафабрик, указывающий, что объект лямбда-выражения должен быть сериализуемым

Методы

Модификатор и тип Метод Описание
static CallSite altMetafactory​(MethodHandles.Lookup caller, String invokedName, MethodType invokedType, Object... args)

Обеспечивает создание простых "функциональных объектов", которые реализуют один или несколько интерфейсов путем делегирования предоставленному MethodHandle после соответствующей адаптации типов и частичной оценки аргументов.

static CallSite metafactory​(MethodHandles.Lookup caller, String invokedName, MethodType invokedType, MethodType samMethodType, MethodHandle implMethod, MethodType instantiatedMethodType)

Обеспечивает создание простых "функциональных объектов", которые реализуют один или несколько интерфейсов путем делегирования предоставленному MethodHandle после соответствующей адаптации типов и частичной оценки аргументов.

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

clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Поля

FLAG_SERIALIZABLE

public static final int FLAG_SERIALIZABLE

Флаг для альтернативных метафабрик, указывающий, что объект лямбда должен быть сериализуемым

См. также:
Значения константных полей

FLAG_MARKERS

public static final int FLAG_MARKERS

Флаг для альтернативных метафабрик, указывающий, что объект лямбда реализует другие маркерные интерфейсы помимо Serializable

См. также:
Значения константных полей

FLAG_BRIDGES

public static final int FLAG_BRIDGES

Флаг для альтернативных метафабрик, указывающий, что объекту лямбда требуются дополнительные методы моста

См. также:
Значения константных полей

Методы

metafactory

public static CallSite metafactory(MethodHandles.Lookup caller,
                                   String invokedName,
                                   MethodType invokedType,
                                   MethodType samMethodType,
                                   MethodHandle implMethod,
                                   MethodType instantiatedMethodType)
                            throws LambdaConversionException

Обеспечивает создание простых "объектов функций", которые реализуют один или несколько интерфейсов путем делегирования предоставленному MethodHandle после соответствующей адаптации типов и частичной оценки аргументов. Обычно используется как метод-загрузчик для invokedynamic мест вызова, чтобы поддержать выражения лямбда и выражения ссылки на метод в языке программирования Java.

Это стандартная, оптимизированная метафабрика; дополнительная гибкость обеспечивается altMetafactory(MethodHandles.Lookup, String, MethodType, Object...). Общее описание поведения этого метода представлено в above.

Когда целевой объект CallSite возвращённый этим методом, вызываются, результирующие объекты функций являются экземплярами класса, который реализует интерфейс, указанный возвращаемым типом invokedType, объявляет метод с именем, заданным invokedName, и сигнатурой, заданной samMethodType. Он также может переопределять дополнительные методы из Object.

Параметры:
caller - Представляет контекст поиска с правами доступа вызывающего. В частности, контекст поиска должен иметь права частного доступа. При использовании с invokedynamic, это автоматически добавляется в стек виртуальной машины.
invokedName - Имя метода для реализации. При использовании с invokedynamic, это предоставляется NameAndType структуры InvokeDynamic и автоматически добавляется в стек виртуальной машины.
invokedType - Ожидаемая сигнатура CallSite. Типы параметров представляют типы переменных захвата; возвращаемый тип — это реализуемый интерфейс. При использовании с invokedynamic, это предоставляется NameAndType структуры InvokeDynamic и автоматически добавляется в стек виртуальной машины. В случае, если метод реализации является методом экземпляра и у этой сигнатуры есть какие-либо параметры, первый параметр в сигнатуре вызова должен соответствовать получателю.
samMethodType - Подпись и возвращаемый тип метода, который должен быть реализован объектом функции.
implMethod - Прямой обработчик метода, описывающий реализующий метод, который должен вызываться (с соответствующей адаптацией типов аргументов, типов возврата и с предварительно добавленными захваченными аргументами к аргументам вызова) во время вызова.
instantiatedMethodType - Подпись и возвращаемый тип, которые должны быть динамически применены во время вызова. Может быть тем же, что и samMethodType, или может быть его специализацией.
Возвращает:
CallSite, целевой объект которого можно использовать для выполнения захвата, генерируя экземпляры интерфейса, указанного invokedType
Выбрасывает:
LambdaConversionException - Если какие-либо из инвариантов связывания, описанных в above, нарушены, или контекст поиска не имеет привилегий частного доступа.

altMetafactory

public static CallSite altMetafactory(MethodHandles.Lookup caller,
                                      String invokedName,
                                      MethodType invokedType,
                                      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 invokedName,
                          MethodType invokedType,
                          Object... args)

но он ведет себя так, как если бы список аргументов был следующим:

CallSite altMetafactory(MethodHandles.Lookup caller,
                          String invokedName,
                          MethodType invokedType,
                          MethodType samMethodType,
                          MethodHandle implMethod,
                          MethodType instantiatedMethodType,
                          int flags,
                          int markerInterfaceCount,  // IF flags has MARKERS set
                          Class... markerInterfaces, // IF flags has MARKERS set
                          int bridgeCount,           // IF flags has BRIDGES set
                          MethodType... bridges      // IF flags has BRIDGES set
                          )

Аргументы, которые появляются в списке аргументов для metafactory(MethodHandles.Lookup, String, MethodType, MethodType, MethodHandle, MethodType) имеют ту же спецификацию, что и в этом методе. Дополнительные аргументы интерпретируются следующим образом:

  • flags указывает дополнительные параметры; это побитовое ИЛИ желаемых флагов. Определенные флаги — FLAG_BRIDGES, FLAG_MARKERS и FLAG_SERIALIZABLE.
  • markerInterfaceCount — количество дополнительных интерфейсов, которые должен реализовать объект функции, и присутствует только в том случае, если установлен флаг FLAG_MARKERS.
  • markerInterfaces — список дополнительных интерфейсов для реализации, длина которого равна markerInterfaceCount, и присутствует только в том случае, если установлен флаг FLAG_MARKERS.
  • bridgeCount — количество дополнительных сигнатур методов, которые должен реализовать объект функции, и присутствует только в том случае, если установлен флаг FLAG_BRIDGES.
  • bridges — список дополнительных сигнатур методов для реализации, длина которого равна bridgeCount, и присутствует только в том случае, если установлен флаг FLAG_BRIDGES.

Каждый класс, указанный markerInterfaces, подчиняется тем же ограничениям, что и Rd, возвращаемый тип invokedType, как описано в above. Каждый MethodType указанный bridges, подчиняется тем же ограничениям, что и samMethodType, как описано в above.

Когда FLAG_SERIALIZABLE установлен в flags, объекты функций будут реализовывать Serializable, и у них будет метод writeReplace, который возвращает соответствующий SerializedLambda. Класс caller должен иметь соответствующий метод $deserializeLambda$, как описано в SerializedLambda.

Когда целевой объект CallSite возвращённый этим методом, вызываются, результирующие объекты функций являются экземплярами класса со следующими свойствами:

  • Класс реализует интерфейс, указанный возвращаемым типом invokedType, и любые интерфейсы, указанные в markerInterfaces
  • Класс объявляет методы с именем, заданным invokedName, и сигнатурой, заданной samMethodType, и дополнительными сигнатурами, заданными bridges
  • Класс может переопределять методы из Object, и может реализовывать методы, связанные с сериализацией.
Параметры:
caller - Представляет контекст поиска с правами доступа вызывающего. В частности, контекст поиска должен иметь права частного доступа. При использовании с invokedynamic, это автоматически добавляется в стек виртуальной машины.
invokedName - Имя метода для реализации. При использовании с invokedynamic, это предоставляется NameAndType структуры InvokeDynamic и автоматически добавляется в стек виртуальной машины.
invokedType - Ожидаемая сигнатура CallSite. Типы параметров представляют типы переменных захвата; возвращаемый тип — это реализуемый интерфейс. При использовании с invokedynamic, это предоставляется NameAndType структуры InvokeDynamic и автоматически добавляется в стек виртуальной машины. В случае, если метод реализации является методом экземпляра и у этой сигнатуры есть какие-либо параметры, первый параметр в сигнатуре вызова должен соответствовать получателю.
args - Массив Object[] содержащий необходимые аргументы samMethodType, implMethod, instantiatedMethodType, flags, и любые необязательные аргументы, как описано в altMetafactory(MethodHandles.Lookup, String, MethodType, Object...) выше}
Возвращает:
CallSite, целевой объект которого можно использовать для выполнения захвата, генерируя экземпляры интерфейса, указанного invokedType
Выбрасывает:
LambdaConversionException - Если какие-либо из инвариантов связывания, описанных в above, нарушены, или контекст поиска не имеет привилегий частного доступа.

© 1993, 2020, 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/11/docs/api/java.base/java/lang/invoke/LambdaMetafactory.html

Spec-Zone .ru
спецификации, руководства, описания, API