Класс LambdaMetafactory
- java.lang.Object
-
- java.lang.invoke.LambdaMetafactory
public class LambdaMetafactory extends Object
Методы для облегчения создания простых "функциональных объектов", которые реализуют один или несколько интерфейсов путём делегирования предоставленному MethodHandle, возможно, после адаптации типов и частичной оценки аргументов. Эти методы обычно используются как методы-загрузчики для invokedynamic мест вызова, для поддержки лямбда-выражений и ссылок на методы в языке программирования Java.
Непрямой доступ к поведению, заданному предоставленным MethodHandle, происходит поэтапно через три фазы:
-
Связывание происходит при вызове методов в этом классе. Они принимают в качестве аргументов интерфейс, подлежащий реализации (обычно функциональный интерфейс, с одним абстрактным методом), имя и сигнатуру метода из этого интерфейса, подлежащего реализации, дескриптор метода, описывающий желаемое поведение реализации для этого метода, и, возможно, другую дополнительную метаданные, и создают
CallSite, цель которого может быть использована для создания соответствующих функциональных объектов. Связывание может включать динамическую загрузку нового класса, реализующего целевой интерфейс.CallSiteможно рассматривать как "фабрику" функциональных объектов, поэтому эти методы связывания называются "метафабриками". -
Захват происходит при вызове цели
CallSite, обычно черезinvokedynamicместо вызова, создавая функциональный объект. Это может происходить многократно для одной фабрикиCallSite. Захват может включать выделение нового функционального объекта или возвращение существующего функционального объекта. ПоведениеMethodHandleможет иметь дополнительные параметры помимо параметров указанного метода интерфейса; эти параметры называются захваченными параметрами, которые должны быть предоставлены в качестве аргументов целевому объектуCallSite, и которые могут быть связаны с поведениемMethodHandleв начале. Количество захваченных параметров и их типы определяются во время связывания. -
Вызов происходит при вызове реализованного метода интерфейса на функциональном объекте. Это может происходить многократно для одного функционального объекта. Метод, на который ссылается поведение
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...). Альтернативная версия является обобщением стандартной версии, предоставляя дополнительный контроль над поведением сгенерированных функциональных объектов через флаги и дополнительные аргументы. Альтернативная версия добавляет возможность управления следующими атрибутами функциональных объектов:
-
Мостирование. Иногда полезно реализовать несколько вариантов сигнатуры метода, включая адаптацию аргументов или типов возврата. Это происходит, когда несколько различных сигнатур VM для метода логически считаются одним методом языком. Флаг
FLAG_BRIDGESуказывает, что будет предоставлен список дополнительныхMethodType, каждый из которых будет реализован результирующим функциональным объектом. Эти методы будут иметь одинаковое имя и инстанцированный тип. -
Несколько интерфейсов. При необходимости, функциональный объект может реализовывать более одного интерфейса. (Эти дополнительные интерфейсы обычно являются маркерными интерфейсами без методов.) Флаг
FLAG_MARKERSуказывает, что будет предоставлен список дополнительных интерфейсов, каждый из которых должен быть реализован результирующим функциональным объектом. -
Сериализация. Сгенерированные функциональные объекты, как правило, не поддерживают сериализацию. Если необходимо,
FLAG_SERIALIZABLEможно использовать для указания, что функциональные объекты должны быть сериализуемыми. Сериализуемые функциональные объекты будут использовать в качестве своей сериализованной формы экземпляры классаSerializedLambda, что требует дополнительной помощи от захватывающего класса (класса, описанного параметромMethodHandles.Lookupcaller); см.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 является пустым, или тип возврата Ra не является пустым и адаптируем к Rt
Кроме того, во время захвата, если implMethod соответствует методу экземпляра и существуют какие-либо аргументы захвата (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.
- Примечание реализации:
- Метод реализации описывается дескриптором метода. Теоретически, может быть использован любой дескриптор метода. В настоящее время поддерживаются прямые дескрипторы методов, представляющие вызов виртуальных, интерфейсных, конструкторских и статических методов.
Поля
| Модификатор и тип | Поле и описание |
|---|---|
static int |
FLAG_BRIDGES Флаг для альтернативных метафабрик, указывающий, что объекту лямбда необходимы дополнительные мостовые методы |
static int |
FLAG_MARKERS Флаг для альтернативных метафабрик, указывающий, что объект лямбда реализует другие маркерные интерфейсы помимо Serializable |
static int |
FLAG_SERIALIZABLE Флаг для альтернативных метафабрик, указывающий, что объект лямбда должен быть сериализуемым |
Конструкторы
| Конструктор и описание |
|---|
LambdaMetafactory() |
Методы
| Модификатор и тип | Метод и описание |
|---|---|
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) Обеспечивает создание простых "функциональных объектов", реализующих один или несколько интерфейсов путем делегирования предоставленному |
Methods inherited from class 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
Флаг для альтернативных метафабрик, указывающий, что объекту лямбда требуются дополнительные мостовые методы
- См. также:
- Значения константных полей
Конструкторы
LambdaMetafactory
public LambdaMetafactory()
Методы
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.
Если в flags установлен флаг FLAG_SERIALIZABLE, функциональные объекты будут реализовывать 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.