Класс MethodHandle
- java.lang.Object
-
- java.lang.invoke.MethodHandle
public abstract class MethodHandle extends Object
Обработчик метода — это типизированная, непосредственно исполняемая ссылка на базовый метод, конструктор, поле или аналогичную низкоуровневую операцию с необязательными преобразованиями аргументов или возвращаемых значений. Эти преобразования довольно общие и включают такие паттерны, как преобразование, вставку, удаление и замену.
Содержимое обработчика метода
Обработчики методов динамически и строго типизируются в соответствии с типами своих параметров и возвращаемых значений. Они не различаются по имени или определяющему классу своих базовых методов. Обработчик метода должен вызываться с помощью символьного описателя типа, который соответствует собственному описателю типа обработчика. Каждый обработчик метода сообщает свой описатель типа через type аксессор. Этот описатель типа — это MethodType объект, структура которого представляет собой серию классов, один из которых является типом возвращаемого значения метода (или void.class в случае отсутствия).
Тип обработчика метода управляет типами вызовов, которые он принимает, и видами преобразований, которые к нему применяются.
Обработчик метода содержит пару специальных методов вызова, называемых invokeExact и invoke. Оба метода вызова обеспечивают прямой доступ к базовому методу, конструктору, полю или другой операции обработчика метода, как модифицировано преобразованиями аргументов и возвращаемых значений. Оба вызова принимают вызовы, которые точно соответствуют собственному типу обработчика метода. Простой, неточный вызов также принимает ряд других типов вызовов.
Обработчики методов неизменяемы и не имеют видимого состояния. Конечно, они могут быть связаны с базовыми методами или данными, которые демонстрируют состояние. Что касается модели памяти Java, любой обработчик метода будет вести себя так, как будто все его (внутренние) поля являются конечными переменными. Это означает, что любой обработчик метода, доступный приложению, всегда будет полностью сформирован. Это верно даже в том случае, если обработчик метода публикуется через общую переменную в гонке данных.
Обработчики методов не могут быть подклассифицированы пользователем. Реализации могут (или не могут) создавать внутренние подклассы MethodHandle, которые могут быть видны через операцию Object.getClass. Программист не должен делать выводы об обработчике метода из его конкретного класса, так как иерархия классов обработчика метода (если таковая есть) может время от времени или в реализациях разных поставщиков меняться.
Компиляция обработчика метода
Выражение вызова метода Java, называющееinvokeExact или invoke, может вызывать обработчик метода из исходного кода Java. С точки зрения исходного кода, эти методы могут принимать любые аргументы, и их результат может быть приведен к любому типу возвращаемого значения. Формально это достигается путем присвоения методам вызова Object типов возвращаемых значений и аргументов с переменной арностью Object, но у них есть дополнительное свойство, называемое полиморфизмом сигнатуры, которое связывает эту свободу вызова непосредственно со стеком выполнения JVM. Как обычно для виртуальных методов, вызовы на уровне исходного кода invokeExact и invoke компилируются в инструкцию invokevirtual. Более необычно, компилятор должен записывать фактические типы аргументов и не может выполнять преобразования вызовов методов над аргументами. Вместо этого он должен поместить их в стек в соответствии с их собственными не преобразованными типами. Объект обработчика метода помещается в стек перед аргументами. Затем компилятор вызывает обработчик метода с символьным описателем типа, описывающим типы аргументов и возвращаемого значения.
Для выдачи полного символьного описателя типа компилятор также должен определить тип возвращаемого значения. Это основано на приведении к типу выражения вызова метода, если оно есть, или же Object, если вызов является выражением, или void, если вызов является оператором. Приведение может быть к примитивному типу (но не void).
В качестве крайнего случая не приведенному к типу null аргументу присваивается символьный описатель типа java.lang.Void. Неопределенность с типом Void безвредна, так как нет ссылок типа Void за исключением нулевой ссылки.
Вызов обработчика метода
При первом выполнении инструкцииinvokevirtual она связывается путем символического разрешения имен в инструкции и проверки того, что вызов метода статически допустим. Это верно для вызовов invokeExact и invoke. В этом случае символьный описатель типа, выданный компилятором, проверяется на корректность синтаксиса, и имена в нем разрешаются. Таким образом, инструкция invokevirtual, которая вызывает обработчик метода, всегда свяжется, если символьный описатель типа имеет правильный синтаксис, и типы существуют. Когда инструкция invokevirtual выполняется после связывания, JVM сначала проверяет тип получаемого обработчика метода, чтобы убедиться, что он соответствует символьному описателю типа. Если соответствие типа не выполняется, это означает, что метод, который вызывает вызывающая сторона, не присутствует в индивидуальном обработчике метода, к которому обращаются.
В случае invokeExact, описатель типа вызова (после разрешения символических имен типов) должен точно соответствовать типу метода получаемого обработчика метода. В случае простого, неточного invoke, разрешенный описатель типа должен быть допустимым аргументом для метода получателя asType. Таким образом, простой invoke более допускает, чем invokeExact.
После соответствия типов вызов invokeExact непосредственно и немедленно вызывает базовый метод обработчика метода (или другое поведение, в зависимости от ситуации).
Вызов простого invoke работает так же, как вызов invokeExact, если символьный описатель типа, указанный вызывающей стороной, точно соответствует собственному типу обработчика метода. Если существует несоответствие типов, invoke пытается скорректировать тип получаемого обработчика метода, как если бы это был вызов asType, чтобы получить обработчик метода, который можно точно вызвать M2. Это позволяет более мощное согласование типа метода между вызывающей и вызываемой сторонами.
(Примечание: настраиваемый обработчик метода M2 не является непосредственно наблюдаемым, и поэтому реализации не обязаны его материализовывать.)
Проверка вызова
В типичных программах соответствие типов обработчика метода обычно будет успешным. Но если соответствие не выполняется, JVM сгенерирует исключениеWrongMethodTypeException, либо напрямую (в случае invokeExact), либо косвенно, как если бы вызов asType не удался (в случае invoke). Таким образом, несоответствие типа метода, которое может проявиться как ошибка связывания в статически типизированной программе, может проявляться как динамическая ошибка WrongMethodTypeException в программе, использующей обработчики методов.
Поскольку типы методов содержат «живые» Class объекты, соответствие типов методов учитывает как имена типов, так и загрузчики классов. Таким образом, даже если обработчик метода M создан в одном загрузчике классов L1 и используется в другом L2, вызовы обработчика метода являются безопасными с точки зрения типов, так как символьный описатель типа вызывающей стороны, как он разрешен в L2, сопоставляется с исходным символьным описателем типа метода вызываемой стороны, как он разрешен в L1. Разрешение в L1 происходит, когда M создается, и его типу присваивается значение, в то время как разрешение в L2 происходит, когда инструкция invokevirtual связывается.
Помимо проверки описателей типов, возможности обработчика метода вызывать его базовый метод не ограничены. Если обработчик метода сформирован на основе недоступного метода классом, имеющим доступ к этому методу, полученный обработчик может использоваться в любом месте любым вызывающим, который получает ссылку на него.
В отличие от API отражения ядра, где проверка доступа выполняется каждый раз при вызове рефлексивного метода, проверка доступа к обработчику метода выполняется при создании обработчика метода. В случае ldc (см. ниже), проверка доступа выполняется в рамках связывания записи константного пула, лежащей в основе константного обработчика метода.
Таким образом, обработчики недоступных методов или методов недоступных классов, как правило, должны храниться в секрете. Их не следует передавать недоверенному коду, если их использование недоверенным кодом не будет безвредным.
Создание обработчика метода
Код Java может создать обработчик метода, который напрямую обращается к любому методу, конструктору или полю, доступному этому коду. Это делается через рефлексивный, основанный на возможностях API, называемыйMethodHandles.Lookup. Например, статический обработчик метода может быть получен из Lookup.findStatic. Также существуют методы преобразования из объектов API отражения ядра, таких как Lookup.unreflect. Как классы и строки, обработчики методов, соответствующие доступным полям, методам и конструкторам, также могут быть представлены напрямую в константном пуле файла класса в качестве констант, которые будут загружаться байткодами ldc. Новый тип записи константного пула, CONSTANT_MethodHandle, напрямую ссылается на связанную запись константного пула CONSTANT_Methodref, CONSTANT_InterfaceMethodref, или CONSTANT_Fieldref. (Для получения полной информации о константах обработчика метода см. разделы 4.4.8 и 5.4.3.5 спецификации Java Virtual Machine.)
Обработчики методов, полученные при поиске или загрузке констант из методов или конструкторов с модификатором переменной арности (0x0080), имеют соответствующую переменную арность, как если бы они были определены с помощью asVarargsCollector.
Ссылка на метод может ссылаться либо на статический, либо на нестатический метод. В случае нестатического метода тип обработчика метода включает явный аргумент получателя, добавленный перед любыми другими аргументами. В типе обработчика метода начальный аргумент получателя типизируется в соответствии с классом, в рамках которого метод был первоначально запрошен. (Например, если нестатический обработчик метода получен через ldc, тип получателя — это класс, указанный в записи константного пула.)
Константы обработчиков методов подвергаются тем же проверкам доступа во время связывания, что и соответствующие инструкции байткода, и инструкция ldc выбросит соответствующие ошибки связывания, если бы поведение байткода выбросило такие ошибки.
В качестве следствия из этого, доступ к защищённым членам ограничен только получателями из класса доступа или одного из его подклассов, а сам класс доступа должен, в свою очередь, быть подклассом (или пакетом-сиблингом) определяющего класса защищённого члена. Если ссылка на метод относится к защищённому нестатическому методу или полю класса вне текущего пакета, аргумент получателя будет сужен до типа класса доступа.
При вызове дескриптора метода виртуального метода метод всегда ищется в получателе (то есть, в первом аргументе).
Также может быть создан дескриптор невиртуального метода для конкретной реализации виртуального метода. Они не выполняют виртуальный поиск на основе типа получателя. Такой дескриптор метода имитирует действие инструкции invokespecial для того же метода.
Примеры использования
Вот некоторые примеры использования:Object x, y; String s; int i;
MethodType mt; MethodHandle mh;
MethodHandles.Lookup lookup = MethodHandles.lookup();
// mt is (char,char)String
mt = MethodType.methodType(String.class, char.class, char.class);
mh = lookup.findVirtual(String.class, "replace", mt);
s = (String) mh.invokeExact("daddy",'d','n');
// invokeExact(Ljava/lang/String;CC)Ljava/lang/String;
assertEquals(s, "nanny");
// weakly typed invocation (using MHs.invoke)
s = (String) mh.invokeWithArguments("sappy", 'p', 'v');
assertEquals(s, "savvy");
// mt is (Object[])List
mt = MethodType.methodType(java.util.List.class, Object[].class);
mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
assert(mh.isVarargsCollector());
x = mh.invoke("one", "two");
// invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
assertEquals(x, java.util.Arrays.asList("one","two"));
// mt is (Object,Object,Object)Object
mt = MethodType.genericMethodType(3);
mh = mh.asType(mt);
x = mh.invokeExact((Object)1, (Object)2, (Object)3);
// invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
assertEquals(x, java.util.Arrays.asList(1,2,3));
// mt is ()int
mt = MethodType.methodType(int.class);
mh = lookup.findVirtual(java.util.List.class, "size", mt);
i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));
// invokeExact(Ljava/util/List;)I
assert(i == 3);
mt = MethodType.methodType(void.class, String.class);
mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt);
mh.invokeExact(System.out, "Hello, world.");
// invokeExact(Ljava/io/PrintStream;Ljava/lang/String;)V Каждый из вышеуказанных вызовов invokeExact или просто invoke генерирует одну инструкцию invokevirtual со символическим дескриптором типа, указанным в следующем комментарии. В этих примерах предполагается, что вспомогательный метод assertEquals — это метод, который вызывает Objects.equals у своих аргументов и утверждает, что результат равен true. Исключения
МетодыinvokeExact и invoke объявлены как выбрасывающие Throwable, что означает, что нет статического ограничения на то, что может выбросить метод-дескриптор. Поскольку JVM не различает проверенные и непроверенные исключения (кроме, конечно, их класса), на форме байткода нет конкретного эффекта от приписывания проверенных исключений вызовам метода-дескрипторов. Но в коде Java методы, которые выполняют вызовы с помощью метода-дескрипторов, должны либо явно выбрасывать Throwable, либо должны ловить все исключения локально, повторно выбрасывая только те, которые разрешены в контексте, и обертывая те, которые не разрешены. Полиморфизм сигнатуры
Необычное поведение компиляции и компоновкиinvokeExact и просто invoke обозначается термином полиморфизм сигнатуры. Как определено в Спецификации языка Java, метод с полиморфизмом сигнатуры — это метод, который может работать с любым набором сигнатур вызовов и типов возвращаемых значений. В исходном коде вызов метода с полиморфизмом сигнатуры будет компилироваться независимо от запрошенного символического дескриптора типа. Как обычно, компилятор Java генерирует инструкцию invokevirtual с заданным символическим дескриптором типа для названного метода. Необычным является то, что символический дескриптор типа выводится из фактических типов аргументов и возвращаемых значений, а не из объявления метода.
Когда JVM обрабатывает байткод, содержащий вызовы с полиморфизмом сигнатуры, он успешно свяжет любой такой вызов независимо от его символического дескриптора типа. (Для сохранения безопасности типов JVM будет защищать такие вызовы с помощью соответствующих динамических проверок типов, как описано в другом месте.)
Генераторы байткода, включая бэкэнд компилятора, должны генерировать необработанные символические дескрипторы типов для этих методов. Инструменты, определяющие символическую привязку, должны принимать такие необработанные дескрипторы без сообщений об ошибках привязки.
Взаимодействие между дескрипторами методов и ядром API Reflection
Используя фабричные методы в APILookup, любой член класса, представленный объектом API Core Reflection, может быть преобразован в эквивалентный дескриптор метода. Например, рефлексивный Method может быть преобразован в дескриптор метода с помощью Lookup.unreflect. Полученные дескрипторы методов обычно обеспечивают более прямой и эффективный доступ к базовым членам класса. В качестве специального случая, когда API Core Reflection используется для просмотра методов с полиморфизмом сигнатуры invokeExact или просто invoke в этом классе, они отображаются как обычные неполиморфные методы. Их рефлексивный вид, как отображается Class.getDeclaredMethod, не затрагивается их специальным статусом в этом API. Например, Method.getModifiers будет сообщать именно те биты модификаторов, которые требуются для любого аналогично объявленного метода, в том числе в данном случае биты native и varargs.
Как и любой отражённый метод, эти методы (когда отражены) могут быть вызваны через java.lang.reflect.Method.invoke. Однако такие рефлексивные вызовы не приводят к вызовам с помощью дескрипторов методов. Такой вызов, если ему передать требуемый аргумент (единственный, типа Object[]), проигнорирует аргумент и выбросит UnsupportedOperationException.
Поскольку инструкции invokevirtual могут напрямую вызывать дескрипторы методов при любом символическом дескрипторе типа, это рефлексивное представление конфликтует с обычным представлением этих методов с помощью байткода. Таким образом, эти два метода, когда просматриваются рефлексивно с помощью Class.getDeclaredMethod, могут рассматриваться только как заглушки.
Чтобы получить метод вызова для определённого дескриптора типа, используйте MethodHandles.exactInvoker или MethodHandles.invoker. API Lookup.findVirtual также может вернуть дескриптор метода для вызова invokeExact или просто invoke, для любого указанного дескриптора типа.
Взаимодействие между дескрипторами методов и дженериками Java
Дескриптор метода может быть получен для метода, конструктора или поля, объявленного с использованием дженериков Java. Как и с API Core Reflection, тип дескриптора метода будет построен из стирания типов уровня исходного кода. Когда дескриптор метода вызывается, типы его аргументов или типа возвращаемого значения могут быть дженерическими типами или экземплярами типов. Если это произойдёт, компилятор заменит эти типы их стираниями, когда он создаёт символический дескриптор типа для инструкцииinvokevirtual. Дескрипторы методов не представляют свои функциональные типы в терминах параметризованных (дженеризованных) типов Java, потому что есть три несоответствия между функциональными типами и параметризованными типами Java.
- Типы методов охватывают все возможные арности, от отсутствия аргументов до максимального количества разрешённых аргументов. Дженерики не являются вариативными и поэтому не могут это представить.
- Типы методов могут определять аргументы примитивных типов, а типы дженериков Java не могут охватывать их.
- Функции высшего порядка над дескрипторами методов (комбинаторы) часто являются дженериками для широкого класса типов функций, включая функции с различными арностями. Невозможно представить такую дженеричность с параметром типа Java.
Ограничения арности
JVM накладывает абсолютное ограничение в 255 стековых аргументов на все методы и конструкторы любого типа. Это ограничение может показаться более строгим в определённых случаях:- Аргумент
longилиdoubleучитывается (с точки зрения ограничений арности) как два слота аргумента. - Нестатический метод потребляет дополнительный аргумент для объекта, на котором вызывается метод.
- Конструктор потребляет дополнительный аргумент для объекта, который строится.
- Поскольку метод-дескриптор
invokeметода (или другого метода с полиморфизмом сигнатуры) не является виртуальным, он потребляет дополнительный аргумент для самого дескриптора метода, помимо любого невиртуального объекта получателя.
IllegalArgumentException. В частности, тип дескриптора метода не должен иметь арность, равную точно максимальной арности 255.- См. также:
-
MethodType,MethodHandles
Методы
| Модификатор и тип | Метод и описание |
|---|---|
MethodHandle |
asCollector(Class<?> arrayType,
int arrayLength) Создаёт обработчик метода, принимающий заданное количество позиционных аргументов и собирающий их в массив. |
MethodHandle |
asFixedArity() Создаёт обработчик метода с фиксированной арностью, который в остальном эквивалентен текущему обработчику метода. |
MethodHandle |
asSpreader(Class<?> arrayType,
int arrayLength) Создаёт обработчик метода, принимающий массив в качестве аргумента и разворачивающий его элементы в позиционные аргументы. |
MethodHandle |
asType(MethodType newType) Создаёт обработчик адаптера метода, который адаптирует тип текущего обработчика метода к новому типу. |
MethodHandle |
asVarargsCollector(Class<?> arrayType) Создаёт адаптер с переменной арностью, способный принимать любое количество позиционных аргументов и собирать их в массив. |
MethodHandle |
bindTo(Object x) Связывает значение |
Object |
invoke(Object... args) Вызывает обработчик метода, разрешая любой тип вызывающего описателя и, при необходимости, выполняя преобразования аргументов и возвращаемых значений. |
Object |
invokeExact(Object... args) Вызывает обработчик метода, разрешая любой тип вызывающего описателя, но требуя точного соответствия типов. |
Object |
invokeWithArguments(List<?> arguments) Выполняет вызов с переменной арностью, передавая аргументы в заданном массиве обработчику метода, как если бы это был неточный |
Object |
invokeWithArguments(Object... arguments) Выполняет вызов с переменной арностью, передавая аргументы в данном списке обработчику метода, как если бы это был неточный |
boolean |
isVarargsCollector() Определяет, поддерживает ли этот обработчик метода вызовы с переменной арностью. |
String |
toString() Возвращает строковое представление обработчика метода, начинающееся со строки |
MethodType |
type() Возвращает тип этого обработчика метода. |
Методы, унаследованные от класса java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait Методы
type
public MethodType type()
Возвращает тип этого обработчика метода. Каждый вызов этого обработчика метода с помощью invokeExact должен точно соответствовать этому типу.
- Возвращает:
- тип обработчика метода
invokeExact
public final Object invokeExact(Object... args)
throws Throwable Вызывает обработчик метода, разрешая любой тип вызывающего описателя, но требуя точного соответствия типов. Символический тип описателя в месте вызова invokeExact должен точно соответствовать type этого обработчика метода. Преобразования аргументов или возвращаемых значений не допускаются.
При наблюдении этого метода через API Core Reflection он будет отображаться как один нативный метод, принимающий массив объектов и возвращающий объект. Если этот нативный метод вызывается напрямую через java.lang.reflect.Method.invoke, через JNI или косвенно через Lookup.unreflect, будет брошено исключение UnsupportedOperationException.
- Параметры:
-
args- список параметров с сигнатурной полиморфией, статически представленный с помощью varargs - Возвращает:
- результат с сигнатурной полиморфией, статически представленный с помощью
Object - Исключения:
-
WrongMethodTypeException- если тип целевого объекта не идентичен символическому типу описателя вызывающего объекта -
Throwable- любое исключение, брошенное базовым методом, передается без изменений через вызов обработчика метода
invoke
public final Object invoke(Object... args)
throws Throwable Вызывает обработчик метода, разрешая любой тип вызывающего описателя и, при необходимости, выполняя преобразования аргументов и возвращаемых значений.
Если символический тип описателя места вызова точно соответствует type этого обработчика метода, вызов происходит так, как если бы он был сделан с помощью invokeExact.
В противном случае, вызов происходит так, как если бы этот обработчик метода был сначала изменён с помощью вызова asType для адаптации обработчика метода к необходимому типу, а затем вызов происходит как если бы он был сделан с помощью invokeExact на изменённом обработчике метода.
Нет гарантии, что вызов asType действительно будет сделан. Если JVM может предсказать результаты вызова, она может выполнить адаптации непосредственно над аргументами вызывающего объекта и вызвать целевой обработчик метода в соответствии со своим точным типом.
Тип описателя, разрешённый в месте вызова invoke, должен быть допустимым аргументом для метода asType получателя. В частности, вызывающая сторона должна указать ту же арность аргументов, что и арность типа вызываемого объекта, если вызываемый объект не является коллектором с переменной арностью.
При наблюдении этого метода через API Core Reflection он будет отображаться как один нативный метод, принимающий массив объектов и возвращающий объект. Если этот нативный метод вызывается напрямую через java.lang.reflect.Method.invoke, через JNI или косвенно через Lookup.unreflect, будет брошено исключение UnsupportedOperationException.
- Параметры:
-
args- список параметров с сигнатурной полиморфией, статически представленный с помощью varargs - Возвращает:
- результат с сигнатурной полиморфией, статически представленный с помощью
Object - Исключения:
-
WrongMethodTypeException- если тип целевого объекта не может быть адаптирован к символическому типу описателя вызывающего объекта -
ClassCastException- если тип целевого объекта может быть адаптирован к вызывающему объекту, но преобразование ссылки не выполнено -
Throwable- любое исключение, брошенное базовым методом, передаётся без изменений через вызов обработчика метода
invokeWithArguments
public Object invokeWithArguments(Object... arguments)
throws Throwable Выполняет вызов с переменной арностью, передавая аргументы в заданном списке обработчику метода, как если бы это был неточный invoke из места вызова, в котором упоминается только тип Object, и чья арность равна длине списка аргументов.
Выполнение происходит в несколько этапов:
- Определяется длина массива аргументов, как
N. Для null ссылки,N=0. - Определяется общий тип
TNаргументовNкакTN=MethodType.genericMethodType(N). - Оригинальный обработчик метода
MH0приводится к требуемому типу, какMH1 = MH0.asType(TN). - Массив разворачивается в
Nотдельных аргументовA0, .... - Вызывается обработчик метода с изменённым типом над распакованными аргументами: MH1.invokeExact(A0, ...).
- Результат берётся как
Objectссылка.
Из-за действия шага asType, при необходимости применяются следующие преобразования аргументов:
- преобразование ссылки
- распаковка
- расширение преобразований примитивных типов
Результат, возвращаемый вызовом, упаковывается, если это примитивный тип, или приводится к null, если возвращаемый тип void.
Этот вызов эквивалентен следующему коду:
MethodHandle invoker = MethodHandles.spreadInvoker(this.type(), 0); Object result = invoker.invokeExact(this, arguments);
В отличие от полиморфных методов по сигнатуре invokeExact и invoke, invokeWithArguments можно получить обычным способом через API Core Reflection и JNI. Поэтому он может быть использован как мост между нативным или рефлексивным кодом и обработчиками методов.
- Параметры:
-
arguments- аргументы, которые нужно передать целевому объекту - Возвращает:
- результат, возвращенный целевым объектом
- Исключения:
-
ClassCastException- если аргумент не может быть преобразован с помощью преобразования ссылки -
WrongMethodTypeException- если тип целевого объекта не может быть адаптирован для принятия указанного количестваObjectаргументов -
Throwable- любое исключение, брошенное при вызове целевого метода - См. также:
MethodHandles.spreadInvoker(java.lang.invoke.MethodType, int)
invokeWithArguments
public Object invokeWithArguments(List<?> arguments)
throws Throwable Выполняет вызов с переменной арностью, передавая аргументы в заданном списке обработчику метода, как если бы это был неточный invoke из места вызова, в котором упоминается только тип Object, и чья арность равна длине списка аргументов.
Этот метод эквивалентен следующему коду:
invokeWithArguments(arguments.toArray()
- Параметры:
-
arguments- аргументы, которые нужно передать целевому объекту - Возвращает:
- результат, возвращенный целевым объектом
- Исключения:
-
NullPointerException- еслиargumentsявляется null ссылкой -
ClassCastException- если аргумент не может быть преобразован с помощью преобразования ссылки -
WrongMethodTypeException- если тип целевого объекта не может быть адаптирован для принятия указанного количестваObjectаргументов -
Throwable- любое исключение, брошенное при вызове целевого метода
asType
public MethodHandle asType(MethodType newType)
Создает обработчик метода-адаптера, который адаптирует тип текущего обработчика метода к новому типу. Результирующий обработчик метода гарантированно сообщает о типе, равном желаемому новому типу.
Если исходный и новый типы равны, возвращает this.
Новый обработчик метода при вызове выполнит следующие шаги:
- Преобразует входной список аргументов для соответствия списку аргументов исходного обработчика метода.
- Вызывает исходный обработчик метода со преобразованным списком аргументов.
- Преобразует любой возвращаемый результат исходного обработчика метода в тип возвращаемого значения нового обработчика метода.
Этот метод обеспечивает ключевое поведенческое различие между invokeExact и обычным, неточной invoke. Два метода выполняют те же шаги, когда описатель типа вызывающей стороны точно соответствует описателю типа вызываемого объекта, но когда типы различаются, обычный invoke также вызывает asType (или какой-либо внутренний эквивалент), чтобы согласовать типы вызывающей и вызываемой сторон.
Если текущий метод является методом с переменным числом аргументов, преобразование списка аргументов может включать преобразование и сборку нескольких аргументов в массив, как описано в другом месте. Во всех остальных случаях все преобразования применяются попарно, что означает, что каждый аргумент или возвращаемое значение преобразуется ровно в один аргумент или возвращаемое значение (или в отсутствие возвращаемого значения). Применяемые преобразования определяются на основе соответствующих типов компонентов старых и новых типов обработчиков методов.
Пусть T0 и T1 будут соответствующими новыми и старыми типами параметров или старыми и новыми типами возвращаемых значений. В частности, для некоторого допустимого индекса i, пусть T0=newType.parameterType(i) и T1=this.type().parameterType(i). Или же, в другом случае, для значений возврата, пусть T0=this.type().returnType() и T1=newType.returnType(). Если типы совпадают, новый обработчик метода не изменяет соответствующий аргумент или возвращаемое значение (если таковое имеется). В противном случае, если возможно, применяется одно из следующих преобразований:
- Если T0 и T1 — ссылки, применяется приведение типа к T1. (Типы не обязательно должны быть связаны каким-либо определенным образом. Это связано с тем, что динамическое значение null может преобразовываться в любой тип ссылки.)
- Если T0 и T1 — примитивные типы, применяется преобразование вызова метода Java (JLS 5.3), если оно существует. (В частности, T0 должен преобразовываться в T1 с помощью расширяющего преобразования примитивного типа.)
- Если T0 — примитивный тип, а T1 — ссылка, применяется преобразование приведения типа Java (JLS 5.5), если оно существует. (В частности, значение упаковывается из T0 в его класс-обертку, который затем расширяется по мере необходимости до T1.)
- Если T0 — ссылка, а T1 — примитивный тип, в момент выполнения будет применено преобразование распаковки, возможно, за которым следует преобразование вызова метода Java (JLS 5.3) над значением примитивного типа. (Это расширяющие преобразования примитивных типов.) T0 должен быть классом-оберткой или его супертипом. (В случае, когда T0 — Object, это преобразования, разрешенные
java.lang.reflect.Method.invoke.) Преобразование распаковки должно иметь возможность успеха, что означает, что если T0 сам по себе не является классом-оберткой, то должен существовать хотя бы один класс-обертка TW, являющийся подтипом T0, и значение примитивного типа, полученное из TW, может быть расширено до T1. - Если тип возвращаемого значения T1 обозначен как void, любое возвращаемое значение отбрасывается
- Если тип возвращаемого значения T0 — void, а T1 — ссылка, вводится значение null.
- Если тип возвращаемого значения T0 — void, а T1 — примитивный тип, вводится значение ноль.
Преобразование обработчика метода невозможно, если любое из необходимых попарных преобразований невозможно.
В момент выполнения преобразования, применяемые к аргументам или возвращаемым значениям ссылочного типа, могут потребовать дополнительные проверки в момент выполнения, которые могут завершиться неудачей. Операция распаковки может завершиться неудачей, потому что исходная ссылка равна null, что приведет к NullPointerException. Операция распаковки или приведение типа ссылки также может завершиться неудачей при ссылке на объект неверного типа, что приведет к ClassCastException. Хотя операция распаковки может принимать несколько типов оберток, если ни одна из них недоступна, будет брошено исключение ClassCastException.
- Parameters:
-
newType- ожидаемый тип нового обработчика метода - Returns:
- обработчик метода, который делегирует
thisпосле выполнения необходимых преобразований аргументов и организует необходимые преобразования возвращаемых значений - Throws:
-
NullPointerException- еслиnewTypeявляется нулевой ссылкой -
WrongMethodTypeException- если преобразование невозможно - See Also:
MethodHandles.explicitCastArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)
asSpreader
public MethodHandle asSpreader(Class<?> arrayType,
int arrayLength) Создает обработчик метода для распределения массива, который принимает аргумент массива в конце и распространяет его элементы как позиционные аргументы. Новый обработчик метода адаптирует текущий обработчик метода как свой целевой объект. Тип адаптера будет таким же, как тип целевого объекта, за исключением того, что последние arrayLength параметры типа целевого объекта заменяются одним параметром массива типа arrayType.
Если тип элемента массива отличается от любого из соответствующих типов аргументов в исходном целевом объекте, исходный целевой объект адаптируется для непосредственного приема элементов массива, как если бы это делалось путем вызова asType.
При вызове адаптер заменяет аргумент массива в конце элементами массива, каждый как свой собственный аргумент для целевого объекта. (Порядок аргументов сохраняется.) Они преобразуются попарно путем приведения типов и/или распаковки до типов конечных параметров целевого объекта. В конечном итоге вызывается целевой объект. Возвращаемое значение целевого объекта возвращается адаптером без изменений.
Перед вызовом целевого объекта адаптер проверяет, что массив содержит ровно достаточно элементов для правильного количества аргументов для целевого обработчика метода. (Массив также может быть null, когда требуется ноль элементов.)
Если при вызове адаптера предоставленный аргумент массива не имеет правильного количества элементов, адаптер выбросит исключение IllegalArgumentException вместо вызова целевого объекта.
Вот несколько простых примеров обработчиков методов для распределения массивов:
MethodHandle equals = publicLookup()
.findVirtual(String.class, "equals", methodType(boolean.class, Object.class));
assert( (boolean) equals.invokeExact("me", (Object)"me"));
assert(!(boolean) equals.invokeExact("me", (Object)"thee"));
// spread both arguments from a 2-array:
MethodHandle eq2 = equals.asSpreader(Object[].class, 2);
assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));
assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));
// try to spread from anything but a 2-array:
for (int n = 0; n <= 10; n++) {
Object[] badArityArgs = (n == 2 ? null : new Object[n]);
try { assert((boolean) eq2.invokeExact(badArityArgs) && false); }
catch (IllegalArgumentException ex) { } // OK
}
// spread both arguments from a String array:
MethodHandle eq2s = equals.asSpreader(String[].class, 2);
assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));
assert(!(boolean) eq2s.invokeExact(new String[]{ "me", "thee" }));
// spread second arguments from a 1-array:
MethodHandle eq1 = equals.asSpreader(Object[].class, 1);
assert( (boolean) eq1.invokeExact("me", new Object[]{ "me" }));
assert(!(boolean) eq1.invokeExact("me", new Object[]{ "thee" }));
// spread no arguments from a 0-array or null:
MethodHandle eq0 = equals.asSpreader(Object[].class, 0);
assert( (boolean) eq0.invokeExact("me", (Object)"me", new Object[0]));
assert(!(boolean) eq0.invokeExact("me", (Object)"thee", (Object[])null));
// asSpreader and asCollector are approximate inverses:
for (int n = 0; n <= 2; n++) {
for (Class<?> a : new Class<?>[]{Object[].class, String[].class, CharSequence[].class}) {
MethodHandle equals2 = equals.asSpreader(a, n).asCollector(a, n);
assert( (boolean) equals2.invokeWithArguments("me", "me"));
assert(!(boolean) equals2.invokeWithArguments("me", "thee"));
}
}
MethodHandle caToString = publicLookup()
.findStatic(Arrays.class, "toString", methodType(String.class, char[].class));
assertEquals("[A, B, C]", (String) caToString.invokeExact("ABC".toCharArray()));
MethodHandle caString3 = caToString.asCollector(char[].class, 3);
assertEquals("[A, B, C]", (String) caString3.invokeExact('A', 'B', 'C'));
MethodHandle caToString2 = caString3.asSpreader(char[].class, 2);
assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray()));
- Parameters:
-
arrayType- обычноObject[], тип аргумента массива, из которого извлекаются аргументы для распределения -
arrayLength- количество аргументов, которые должны быть распределены из входного аргумента массива - Returns:
- новый обработчик метода, который распределяет свой конечный аргумент массива перед вызовом исходного обработчика метода
- Throws:
-
NullPointerException- еслиarrayTypeявляется нулевой ссылкой -
IllegalArgumentException- еслиarrayTypeне является типом массива, или если целевой объект не имеет как минимумarrayLengthтипов параметров, или еслиarrayLengthотрицательно, или если тип результирующего обработчика метода будет иметь слишком много параметров -
WrongMethodTypeException- если неявный вызовasTypeзавершится неудачей - See Also:
asCollector(java.lang.Class<?>, int)
asCollector
public MethodHandle asCollector(Class<?> arrayType,
int arrayLength) Создаёт обработчик метода для сборки массива, который принимает заданное количество позиционных аргументов и собирает их в аргумент массива. Новый обработчик метода адаптирует текущий обработчик метода как свой целевой объект. Тип адаптера будет таким же, как тип целевого объекта, за исключением того, что один параметр в конце (обычно типа arrayType) заменяется на arrayLength параметрами, тип которых — тип элемента arrayType.
Если тип массива отличается от типа конечного аргумента в исходном целевом объекте, исходный целевой объект адаптируется для непосредственного приема типа массива, как если бы это делалось с помощью вызова asType.
При вызове адаптер заменяет свои конечные arrayLength аргументы одним новым массивом типа arrayType, элементы которого составляют (в порядке) заменённые аргументы. В конечном итоге вызывается целевой объект. Возвращаемое значение целевого объекта возвращается адаптером без изменений.
(Массив также может быть общей константой, когда arrayLength равно нулю.)
(Примечание: arrayType часто идентичен типу последнего параметра исходного целевого объекта. Это явный аргумент для симметрии с asSpreader, а также для того, чтобы целевой объект мог использовать простой Object в качестве своего последнего типа параметра.)
Для создания адаптера сбора, который не ограничен определённым количеством собираемых аргументов, используйте asVarargsCollector вместо этого.
Вот несколько примеров обработчиков методов для сбора массивов:
MethodHandle deepToString = publicLookup()
.findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
assertEquals("[won]", (String) deepToString.invokeExact(new Object[]{"won"}));
MethodHandle ts1 = deepToString.asCollector(Object[].class, 1);
assertEquals(methodType(String.class, Object.class), ts1.type());
//assertEquals("[won]", (String) ts1.invokeExact( new Object[]{"won"})); //FAIL
assertEquals("[[won]]", (String) ts1.invokeExact((Object) new Object[]{"won"}));
// arrayType can be a subtype of Object[]
MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
assertEquals(methodType(String.class, String.class, String.class), ts2.type());
assertEquals("[two, too]", (String) ts2.invokeExact("two", "too"));
MethodHandle ts0 = deepToString.asCollector(Object[].class, 0);
assertEquals("[]", (String) ts0.invokeExact());
// collectors can be nested, Lisp-style
MethodHandle ts22 = deepToString.asCollector(Object[].class, 3).asCollector(String[].class, 2);
assertEquals("[A, B, [C, D]]", ((String) ts22.invokeExact((Object)'A', (Object)"B", "C", "D")));
// arrayType can be any primitive array type
MethodHandle bytesToString = publicLookup()
.findStatic(Arrays.class, "toString", methodType(String.class, byte[].class))
.asCollector(byte[].class, 3);
assertEquals("[1, 2, 3]", (String) bytesToString.invokeExact((byte)1, (byte)2, (byte)3));
MethodHandle longsToString = publicLookup()
.findStatic(Arrays.class, "toString", methodType(String.class, long[].class))
.asCollector(long[].class, 1);
assertEquals("[123]", (String) longsToString.invokeExact((long)123));
- Parameters:
-
arrayType- частоObject[], тип аргумента массива, который будет собирать аргументы -
arrayLength- количество аргументов, которые нужно собрать в новый массив аргументов - Returns:
- новый обработчик метода, который собирает некоторые конечные аргументы в массив перед вызовом исходного обработчика метода
- Throws:
-
NullPointerException- еслиarrayTypeявляется нулевой ссылкой -
IllegalArgumentException- еслиarrayTypeне является типом массива илиarrayTypeне может быть присвоено типу конечного параметра данного обработчика метода, илиarrayLengthне является допустимым размером массива, или тип результирующего обработчика метода будет иметь слишком много параметров -
WrongMethodTypeException- если неявный вызовasTypeзавершится неудачей - See Also:
-
asSpreader(java.lang.Class<?>, int),asVarargsCollector(java.lang.Class<?>)
asVarargsCollector
public MethodHandle asVarargsCollector(Class<?> arrayType)
Создаёт адаптер с переменной арностью, способный принимать любое количество позиционных аргументов в конце и собирать их в массив.
Тип и поведение адаптера будут такими же, как тип и поведение целевого объекта, за исключением того, что определённые invoke и asType запросы могут привести к тому, что позиционные аргументы в конце будут собраны в заключительный параметр целевого объекта. Кроме того, тип последнего параметра адаптера будет arrayType, даже если у целевого объекта другой тип последнего параметра.
Данная трансформация может вернуть this , если обработчик метода уже имеет переменную арность, а тип его заключительного параметра идентичен arrayType.
При вызове с invokeExact, адаптер вызывает целевой объект без изменений аргументов. (Примечание: это поведение отличается от поведения коллектора с фиксированной арностью, поскольку он принимает целый массив неопределённой длины, а не фиксированное число аргументов.)
При вызове с простым неточной invoke, если тип вызывающего объекта совпадает с типом адаптера, адаптер вызывает целевой объект так же, как с invokeExact. (Это нормальное поведение для invoke при совпадении типов.)
В противном случае, если арности вызывающего объекта и адаптера совпадают, и тип заключительного параметра вызывающего объекта является ссылочным типом, идентичным или приводимым к типу заключительного параметра адаптера, аргументы и возвращаемые значения преобразуются попарно, как если бы это выполнялось с помощью asType на обработчике метода с фиксированной арностью.
В противном случае, арности отличаются, или тип заключительного параметра адаптера не может быть приведён к соответствующему типу вызывающего объекта. В этом случае адаптер заменяет все аргументы с позиции заключительного аргумента и далее новым массивом типа arrayType, элементы которого составляют (в порядке) заменённые аргументы.
Тип вызывающего объекта должен предоставлять по крайней мере достаточно аргументов и правильного типа для удовлетворения требований целевого объекта к позиционным аргументам перед аргументом массива в конце. Таким образом, вызывающий объект должен предоставить как минимум N-1 аргументов, где N - арность целевого объекта. Кроме того, должны существовать преобразования из входных аргументов в аргументы целевого объекта. Как и при других использовании простых invoke, если эти базовые требования не выполнены, может быть выброшено исключение WrongMethodTypeException.
Во всех случаях возвращаемое значение целевого объекта возвращается адаптером без изменений.
В последнем случае это точно так же, как если бы целевой обработчик метода временно адаптировался с помощью коллектора с фиксированной арностью до арности, необходимой типу вызывающего объекта. (Как и asCollector, если длина массива равна нулю, может использоваться общий константный элемент вместо нового массива. Если предполагаемый вызов asCollector выбросил бы IllegalArgumentException или WrongMethodTypeException, вызов адаптера с переменной арностью должен выбросить WrongMethodTypeException.)
Поведение asType также специализируется для адаптеров с переменной арностью, чтобы сохранить инвариант, что простой неточный invoke всегда эквивалентен вызову asType для корректировки типа целевого объекта, за которым следует invokeExact. Поэтому адаптер с переменной арностью отвечает на запрос asType путём создания коллектора с фиксированной арностью, если и только если адаптер и запрошенный тип различаются по арности или типу заключительного аргумента. Полученный коллектор с фиксированной арностью дополнительно корректируется (при необходимости) до запрошенного типа путём попарного преобразования, как если бы это выполнялось с помощью другого применения asType.
Когда обработчик метода получается путём выполнения инструкции ldc константы CONSTANT_MethodHandle, и целевой метод отмечен как метод с переменной арностью (с модификатором 0x0080), обработчик метода будет принимать несколько арностей, как если бы константа обработчика метода была создана с помощью вызова asVarargsCollector.
Для создания адаптера сбора, который собирает определённое число аргументов и чей тип отражает это определённое число, используйте asCollector вместо этого.
Ни одна трансформация обработчиков метода не создаёт новых обработчиков метода с переменной арностью, если это не документировано. Поэтому, помимо asVarargsCollector, все методы в MethodHandle и MethodHandles будут возвращать обработчик метода с фиксированной арностью, за исключением случаев, когда они указаны для возврата исходного операнда (например, asType типа обработчика метода).
Вызов asVarargsCollector на обработчике метода, который уже имеет переменную арность, создаст обработчик метода с тем же типом и поведением. Он может (или не может) вернуть исходный обработчик метода с переменной арностью.
Вот пример обработчика метода с переменной арностью для создания списка:
MethodHandle deepToString = publicLookup()
.findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
MethodHandle ts1 = deepToString.asVarargsCollector(Object[].class);
assertEquals("[won]", (String) ts1.invokeExact( new Object[]{"won"}));
assertEquals("[won]", (String) ts1.invoke( new Object[]{"won"}));
assertEquals("[won]", (String) ts1.invoke( "won" ));
assertEquals("[[won]]", (String) ts1.invoke((Object) new Object[]{"won"}));
// findStatic of Arrays.asList(...) produces a variable arity method handle:
MethodHandle asList = publicLookup()
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));
assertEquals(methodType(List.class, Object[].class), asList.type());
assert(asList.isVarargsCollector());
assertEquals("[]", asList.invoke().toString());
assertEquals("[1]", asList.invoke(1).toString());
assertEquals("[two, too]", asList.invoke("two", "too").toString());
String[] argv = { "three", "thee", "tee" };
assertEquals("[three, thee, tee]", asList.invoke(argv).toString());
assertEquals("[three, thee, tee]", asList.invoke((Object[])argv).toString());
List ls = (List) asList.invoke((Object)argv);
assertEquals(1, ls.size());
assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0))); Обсуждение: Эти правила разработаны как динамически типизированный вариант правил Java для методов с переменной арностью. В обоих случаях вызывающие стороны метода или обработчика метода с переменной арностью могут передавать ноль или более позиционных аргументов, или же передавать предварительно собранные массивы любой длины. Пользователи должны понимать особую роль конечного аргумента и влияние соответствия типа на этот конечный аргумент, которое определяет, будет ли один заключительный аргумент интерпретироваться как целый массив или как один элемент массива для сбора. Обратите внимание, что динамический тип заключительного аргумента не влияет на это решение, только сравнение символического описания типа места вызова и описания типа обработчика метода.)
- Параметры:
-
arrayType- частоObject[], тип аргумента массива, который будет собирать аргументы - Возвращает:
- новый обработчик метода, который может собирать любое количество аргументов в конце в массив перед вызовом исходного обработчика метода
- Исключение:
-
NullPointerException- еслиarrayType- ссылка NULL -
IllegalArgumentException- еслиarrayTypeне является типом массива илиarrayTypeне приводим к типу заключительного параметра этого обработчика метода - См. также:
-
asCollector(java.lang.Class<?>, int),isVarargsCollector(),asFixedArity()
isVarargsCollector
public boolean isVarargsCollector()
Определяет, поддерживает ли этот обработчик метода вызовы с переменной арностью. Такие обработчики метода возникают из следующих источников:
- вызов asVarargsCollector
- вызов метода lookup, который разрешает метод или конструктор Java с переменной арностью
- инструкция
ldcконстантыCONSTANT_MethodHandle, которая разрешает метод или конструктор Java с переменной арностью
- Возвращает:
- true, если этот обработчик метода принимает более одной арности простых неточных
invokeвызовов - См. также:
-
asVarargsCollector(java.lang.Class<?>),asFixedArity()
asFixedArity
public MethodHandle asFixedArity()
Создаёт обработчик метода с фиксированной арностью, который в остальном эквивалентен текущему обработчику метода.
Если текущий обработчик метода не имеет переменной арности, возвращается текущий обработчик метода. Это верно даже если текущий обработчик метода не может быть допустимым входом для asVarargsCollector.
В противном случае, полученный обработчик метода с фиксированной арностью имеет тот же тип и поведение, что и текущий обработчик метода, за исключением того, что isVarargsCollector будет false. Обработчик метода с фиксированной арностью может (или не может) быть предыдущим аргументом для asVarargsCollector.
Вот пример обработчика метода с переменной арностью для создания списка:
MethodHandle asListVar = publicLookup()
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
.asVarargsCollector(Object[].class);
MethodHandle asListFix = asListVar.asFixedArity();
assertEquals("[1]", asListVar.invoke(1).toString());
Exception caught = null;
try { asListFix.invoke((Object)1); }
catch (Exception ex) { caught = ex; }
assert(caught instanceof ClassCastException);
assertEquals("[two, too]", asListVar.invoke("two", "too").toString());
try { asListFix.invoke("two", "too"); }
catch (Exception ex) { caught = ex; }
assert(caught instanceof WrongMethodTypeException);
Object[] argv = { "three", "thee", "tee" };
assertEquals("[three, thee, tee]", asListVar.invoke(argv).toString());
assertEquals("[three, thee, tee]", asListFix.invoke(argv).toString());
assertEquals(1, ((List) asListVar.invoke((Object)argv)).size());
assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
- Возвращает:
- новый обработчик метода, который принимает только фиксированное количество аргументов
- См. также:
-
asVarargsCollector(java.lang.Class<?>),isVarargsCollector()
bindTo
public MethodHandle bindTo(Object x)
Связывает значение x с первым аргументом обработчика метода без его вызова. Новый обработчик метода адаптирует текущий обработчик метода, как целевой, связывая его с заданным аргументом. Тип связанного обработчика будет таким же, как тип целевого, за исключением того, что один ведущий параметр ссылки будет опущен.
При вызове связанный обработчик вставляет заданное значение x в качестве нового ведущего аргумента для целевого объекта. Остальные аргументы также передаются без изменений. Возвращаемое значение целевого объекта возвращается связанным обработчиком без изменений.
Ссылка x должна быть преобразуема в тип первого параметра целевого объекта.
(Примечание: поскольку обработчики методов неизменяемы, целевой обработчик метода сохраняет свой исходный тип и поведение.)
- Параметры:
-
x- значение, которое будет связано с первым аргументом целевого объекта - Возвращает:
- новый обработчик метода, который добавляет заданное значение в начало списка входных аргументов перед вызовом исходного обработчика метода
- Исключение:
-
IllegalArgumentException- если целевой объект не имеет ведущего параметра типа, являющегося ссылочным типом -
ClassCastException- еслиxне может быть преобразован в ведущий параметр типа целевого объекта - См. также:
MethodHandles.insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...)
toString
public String toString()
Возвращает строковое представление обработчика метода, начиная со строки "MethodHandle" и заканчивая строковым представлением типа обработчика метода. Другими словами, этот метод возвращает строку, равную значению:
"MethodHandle" + type().toString()
(Примечание: будущие версии этого API могут добавить дополнительную информацию в строковое представление. Поэтому текущий синтаксис не должен анализироваться приложениями.)
© 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.