Класс 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, и которые могут быть связаны с поведением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) | Обеспечивает создание простых "функциональных объектов", которые реализуют один или несколько интерфейсов путем делегирования предоставленному |
static CallSite | metafactory(MethodHandles.Lookup caller,
String invokedName,
MethodType invokedType,
MethodType samMethodType,
MethodHandle implMethod,
MethodType instantiatedMethodType) | Обеспечивает создание простых "функциональных объектов", которые реализуют один или несколько интерфейсов путем делегирования предоставленному |
Методы, объявленные в классе 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