Spec-Zone .ru
спецификации, руководства, описания, API
|
public abstract class MethodHandle extends Object
Каждый дескриптор метода сообщает о своем дескрипторе типа через type
средство доступа. Этот дескриптор типа является a MethodType
объект, структура которого является серией классов, один из которых является типом возврата метода (или void.class
если ни один).
Тип дескриптора метода управляет типами вызовов, которые он принимает, и виды преобразований, которые применяются к нему.
Дескриптор метода содержит пару специальных invoker вызванных методов invokeExact
и invoke
. Оба invoker методы обеспечивают прямой доступ к базовому методу дескриптора метода, конструктору, полю, или другой работе, как изменено преобразованиями параметров и возвращаемых значений. Оба invokers принимают вызовы, которые точно соответствуют собственный тип дескриптора метода. Простой, неточный invoker также принимает диапазон других типов вызова.
Дескрипторы метода являются неизменными и не имеют никакого видимого состояния. Конечно, они могут быть связаны с базовыми методами или данными, которые показывают состояние. Относительно Модели памяти Java будет вести себя любой дескриптор метода, как будто все его (внутренние) поля являются заключительными переменными. Это означает, что любой дескриптор метода, сделанный видимым к приложению, будет всегда полностью формироваться. Это - истина, даже если дескриптор метода публикуется через совместно используемую переменную в гонке данных.
Дескрипторы метода не могут быть разделены на подклассы пользователем. Реализации могут (или не может) создавать внутренние подклассы MethodHandle
который может быть видимым через Object.getClass
работа. Программист не должен сделать выводов о дескрипторе метода от его определенного class как дескриптор метода, который иерархия class (если кто-либо) может время от времени изменять или через реализации от различных поставщиков.
invokeExact
или invoke
может вызвать дескриптор метода от исходного кода Java. С точки зрения исходного кода эти методы могут взять любые параметры, и их результат может быть брошен к любому типу возврата. Формально это выполняется, давая invoker методы Object
возвратите типы и переменную арность Object
параметры, но у них есть дополнительное качество, названное полиморфизмом подписи, который соединяет эту свободу вызова непосредственно к стеку выполнения JVM. Как обычно с виртуальными методами, звонками на уровне источника invokeExact
и invoke
скомпилируйте в invokevirtual
инструкция. Более необычно компилятор должен записать фактические типы параметра, и, возможно, не выполняет преобразования вызова метода на параметрах. Вместо этого это должно продвинуть их на стеке согласно их собственным непреобразованным типам. Объект дескриптора метода продвигается на стеке перед параметрами. Компилятор тогда вызывает дескриптор метода с символьным дескриптором типа, который описывает типы возврата и параметр.
Чтобы выпустить полный символьный дескриптор типа, компилятор должен также определить тип возврата. Это основано на броске по выражению вызова метода, если есть один, или иначе Object
если вызов является выражением или иначе void
если вызов является оператором. Бросок может быть к типу примитива (но нет void
).
Как угловой случай, uncasted null
параметру дают символьный дескриптор типа java.lang.Void
. Неоднозначность с типом Void
безопасно, так как нет никаких ссылок типа Void
кроме нулевой ссылки.
invokevirtual
инструкция выполняется, она соединяется, символически разрешая имена в инструкции и проверяя, что вызов метода является статически законным. Это верно для звонков invokeExact
и invoke
. В этом случае символьный дескриптор типа, испускаемый компилятором, проверяется на корректный синтаксис и имена, которые это содержит, разрешаются. Таким образом, invokevirtual
инструкция, которая вызывает дескриптор метода, будет всегда соединяться, пока символьный дескриптор типа синтаксически правильно построен, и типы существуют. Когда invokevirtual
выполняется после соединения тип дескриптора метода получения сначала проверяется JVM, чтобы гарантировать, что это соответствует символьный дескриптор типа. Если соответствие типа перестало работать, это означает, что метод, который вызывает вызывающая сторона, не присутствует на отдельном вызываемом дескрипторе метода.
В случае invokeExact
, дескриптор типа вызова (после разрешения символьных имен типов) должен точно соответствовать тип метода дескриптора метода получения. В случае простого, неточного invoke
, разрешенный дескриптор типа должен быть допустимым параметром получателю asType
метод. Таким образом, плоскость invoke
является более разрешающим чем invokeExact
.
После соответствия типа, звонка invokeExact
непосредственно и сразу вызовите базовый метод дескриптора метода (или другое поведение, в зависимости от обстоятельств).
Звонок в плоскость invoke
работает то же самое звонком invokeExact
, если символьный дескриптор типа, определенный вызывающей стороной точно, соответствует собственный тип дескриптора метода. Если есть несоответствие типов, invoke
попытки скорректировать тип дескриптора метода получения, как будто звонком asType
, получить точно invokable дескриптор метода M2
. Это позволяет более мощное согласование типа метода между вызывающей стороной и вызываемым.
(Отметьте: скорректированный дескриптор метода M2
не непосредственно заметно, и реализации поэтому не требуются осуществить это.)
WrongMethodTypeException
, любой непосредственно (в случае invokeExact
) или косвенно как будто отказавшим звонком asType
(в случае invoke
). Таким образом несоответствие типов метода, которое могло бы обнаружиться как ошибка редактирования в программе со статическим контролем типов, может обнаружиться как динамическое WrongMethodTypeException
в программе, которая использует дескрипторы метода.
Поскольку типы метода содержат "живой" Class
объекты, тип метода, соответствующий, принимают во внимание и вводят имена и загрузчики class. Таким образом, даже если дескриптор метода M
создается в одном загрузчике class L1
и используемый в другом L2
, вызовы дескриптора метода безопасны с точки зрения типов, потому что символьный дескриптор типа вызывающей стороны, как разрешено в L2
, является соответствующим против символьного дескриптора типа метода исходного вызываемого, как разрешено в L1
. Разрешение в L1
происходит когда M
создается и его тип присваивается, в то время как разрешение в L2
происходит когда invokevirtual
инструкция соединяется.
Кроме проверки дескрипторов типа, возможность дескриптора метода вызвать ее базовый метод неограниченна. Если дескриптор метода формируется о непубличном методе class, у которого есть доступ к тому методу, получающийся дескриптор может использоваться в любом месте любой вызывающей стороной, кто получает ссылку на это.
В отличие от этого с Базовым API Reflection, где доступ проверяется каждый раз, когда отражающий метод вызывается, проверка доступа дескриптора метода выполняется, когда дескриптор метода создается. В случае ldc
(см. ниже), проверка доступа выполняется как часть соединения постоянной записи пула, базовой постоянный дескриптор метода.
Таким образом дескрипторы к непубличным методам, или к методам в непубличных классах, должны обычно держаться в секрете. Их нельзя передать к недоверяемому коду, если их использование из недоверяемого кода не было бы безопасно.
MethodHandles.Lookup
Например, статический дескриптор метода может быть получен из Lookup.findStatic
. Есть также методы преобразования от Базовых объектов API Reflection, такой как Lookup.unreflect
. Как классы и строки, дескрипторы метода, которые соответствуют доступным полям, методам, и конструкторам, могут также быть представлены непосредственно в постоянном пуле файла class как константы, которые будут загружены ldc
байт-коды. Новый тип постоянной записи пула, CONSTANT_MethodHandle
, обращается непосредственно к связанному CONSTANT_Methodref
, CONSTANT_InterfaceMethodref
, или CONSTANT_Fieldref
постоянная запись пула. (Для полного изложения на константах дескриптора метода см. разделы 4.4.8 и 5.4.3.5 из Спецификации виртуальной машины Java.)
Дескрипторы метода, произведенные поисками или постоянными загрузками из методов или конструкторов с переменным битом модификатора арности (0x0080
) имейте соответствующую переменную арность, как будто они были определены с помощью справки asVarargsCollector
.
Ссылка метода может обратиться или к статическому или нестатическому методу. В нестатическом случае тип дескриптора метода включает явный параметр получателя, предварительно ожидаемый перед любыми другими параметрами. В типе дескриптора метода начальный параметр получателя вводится согласно class, под которым первоначально требовали метод. (Например, если нестатический дескриптор метода получается через ldc
, типом получателя является class, названный в постоянной записи пула.)
Константы дескриптора метода подвергаются тем же самым разовым ссылкой проверкам прав доступа свои соответствующие инструкции байт-кода, и ldc
инструкция бросит соответствующие ошибки редактирования, если поведения байт-кода бросили бы такие ошибки.
Как заключение этого, доступ к защищенным элементам ограничивается получателям только доступа class, или один из его подклассов, и доступа, class должен поочередно быть подклассом (или одноуровневый элемент пакета) определения защищенного элемента class. Если ссылка метода обратится к защищенному нестатическому методу или полю class вне текущего пакета, то параметр получателя будет сужен к типу доступа class.
Когда дескриптор метода к виртуальному методу вызывается, метод всегда ищется в получателе (то есть, первый параметр).
Невиртуальный дескриптор метода к определенной виртуальной реализации метода может также быть создан. Они не выполняют виртуальный поиск, основанный на типе получателя. Такой дескриптор метода моделирует эффект 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
на его параметрах, и утверждает, что результатом является истина. invokeExact
и invoke
как объявляют, бросают Throwable
, который должен сказать, что нет никакого статического ограничения на то, что может бросить дескриптор метода. Так как JVM не различает проверенные и исключения непроверенные (кроме их class, конечно), нет никакого определенного эффекта на форму байт-кода от приписывания проверенных исключений к вызовам дескриптора метода. Но в исходном коде Java, методы, которые выполняют вызовы дескриптора метода, должны или явно бросить Throwable
, или иначе должен поймать весь throwables локально, повторно бросая только тех, которые являются законными в контексте, и переносящихся, которые недопустимы. invokeExact
и плоскость invoke
ссылается полиморфизмом подписи термина. Как определено в Спецификации языка Java, подпись полиморфный метод является тем, который может работать с любым широким диапазоном подписей вызова и возвратить типы. В исходном коде звонок в подпись полиморфный метод скомпилирует, независимо от требуемого символьного дескриптора типа. Как обычно компилятор Java испускает invokevirtual
инструкция с данным символьным дескриптором типа против именованного метода. Необычная часть - то, что символьный дескриптор типа получается из фактического параметра и типов возврата, не из объявления метода.
Когда JVM обработает байт-код, содержащий подпись полиморфные вызовы, это успешно соединит любой такой вызов, независимо от его символьного дескриптора типа. (Чтобы сохранить безопасность типов, JVM будет охранять такие вызовы с подходящими динамическими проверками типа, как описано в другом месте.)
Генераторы байт-кода, включая бэкэнд компилятора, обязаны испускать непреобразованные символьные дескрипторы типа для этих методов. Инструменты, которые определяют символьное редактирование, обязаны принимать такие непреобразованные дескрипторы, не сообщая об ошибках редактирования.
Lookup
API, любой элемент class, представленный Базовым объектом API Reflection, может быть преобразован в поведенчески эквивалентный дескриптор метода. Например, отражающее Method
может быть преобразован в использование дескриптора метода Lookup.unreflect
. Получающиеся дескрипторы метода обычно обеспечивают более прямой и эффективный доступ к базовым элементам class. Как особый случай, когда Базовый API Reflection используется, чтобы просмотреть подпись полиморфные методы invokeExact
или плоскость invoke
в этом class они появляются как обычные неполиморфные методы. Их отражающее появление, как просматривающийся Class.getDeclaredMethod
, незатронуто их особым статусом в этом API. Например, Method.getModifiers
сообщит точно о тех битах модификатора, требуемых для любого так же объявленного метода, включая в этом случае native
и varargs
биты.
Как с любым отраженным методом, эти методы (когда отражено) могут быть вызваны через java.lang.reflect.Method.invoke
. Однако, такие отражающие вызовы не приводят к вызовам дескриптора метода. Такой вызов, если передано необходимый параметр (единственный, типа Object[]
), проигнорирует параметр и бросит UnsupportedOperationException
.
С тех пор invokevirtual
инструкции могут исходно вызвать дескрипторы метода под любым символьным дескриптором типа, это отражающее представление конфликты с нормальным представлением этих методов через байт-коды. Таким образом, эти два собственных метода, когда отражающим образом просматривающийся Class.getDeclaredMethod
, может быть расценен как заполнители только.
Чтобы получить invoker метод для определенного дескриптора типа, использовать MethodHandles.exactInvoker
, или MethodHandles.invoker
. Lookup.findVirtual
API также в состоянии возвратить дескриптор метода, чтобы вызвать invokeExact
или плоскость invoke
, для любого указанного дескриптора типа.
invokevirtual
инструкция. Дескрипторы метода не представляют свои подобные функции типы с точки зрения Java параметризованные (универсальные) типы, потому что есть три несоответствия между подобными функции типами и параметризованными типами Java.
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)
Связывает значение
x к первому параметру дескриптора метода, не вызывая это. |
Объект |
invoke(Object... args)
Вызывает дескриптор метода, позволяя любой дескриптор типа вызывающей стороны, и дополнительно выполняя преобразования на параметрах и возвращаемых значениях.
|
Объект |
invokeExact(Object... args)
Вызывает дескриптор метода, позволяя любой дескриптор типа вызывающей стороны, но требуя точного соответствия типа.
|
Объект |
invokeWithArguments(List<?> arguments)
Выполняет переменный вызов арности, передавая параметры в данном массиве к дескриптору метода, как будто через неточное
invoke от сайта вызова, который упоминает только тип Object , и чья арность является длиной массива параметра. |
Объект |
invokeWithArguments(Object... arguments)
Выполняет переменный вызов арности, передавая параметры в данном массиве к дескриптору метода, как будто через неточное
invoke от сайта вызова, который упоминает только тип Object , и чья арность является длиной массива параметра. |
boolean |
isVarargsCollector()
Определяет, поддерживает ли этот дескриптор метода переменные вызовы арности.
|
Строка |
toString()
Возвращает строковое представление дескриптора метода, запускающегося со строки
"MethodHandle" и окончание строковым представлением типа дескриптора метода. |
MethodType |
type()
Сообщает тип этого дескриптора метода.
|
public MethodType type()
invokeExact
должен точно соответствовать этот тип.public final Object invokeExact(Object... args) throws Throwable
invokeExact
должен точно соответствовать этот дескриптор метода type
. Никакие преобразования не позволяются на параметрах или возвращаемых значениях. Когда этот метод будет наблюдаться через Базовый API Reflection, это появится как единственный собственный метод, беря объектный массив и возвращая объект. Если этот собственный метод вызывается непосредственно через java.lang.reflect.Method.invoke
, через JNI, или косвенно через Lookup.unreflect
, это бросит UnsupportedOperationException
.
WrongMethodTypeException
- если тип цели не идентичен с символьным дескриптором типа вызывающей стороныThrowable
- что-либо брошенное базовым методом распространяет неизменный через вызов дескриптора методаpublic final Object invoke(Object... args) throws Throwable
Если символьный дескриптор типа сайта вызова точно соответствует этот дескриптор метода type
, вызов продолжается как будто invokeExact
.
Иначе, вызов продолжается, как будто этот дескриптор метода был сначала скорректирован, вызывая asType
чтобы скорректировать этот дескриптор метода к необходимому типу, и затем вызов продолжается как будто invokeExact
на скорректированном дескрипторе метода.
Нет никакой гарантии что asType
вызов фактически выполняется. Если JVM может предсказать результаты выполнения вызова, это может выполнить адаптацию непосредственно на параметрах вызывающей стороны, и вызвать целевой дескриптор метода согласно его собственному точному типу.
Разрешенный дескриптор типа на сайте вызова invoke
должен быть допустимый параметр получателям asType
метод. В частности вызывающая сторона должна определить ту же самую арность параметра как тип вызываемого, если вызываемый не является переменным коллектором арности.
Когда этот метод будет наблюдаться через Базовый API Reflection, это появится как единственный собственный метод, беря объектный массив и возвращая объект. Если этот собственный метод вызывается непосредственно через java.lang.reflect.Method.invoke
, через JNI, или косвенно через Lookup.unreflect
, это бросит UnsupportedOperationException
.
WrongMethodTypeException
- если тип цели не может быть скорректирован к символьному дескриптору типа вызывающей стороныClassCastException
- если тип цели может быть скорректирован к вызывающей стороне, но ссылочный бросок перестал работатьThrowable
- что-либо брошенное базовым методом распространяет неизменный через вызов дескриптора методаpublic Object invokeWithArguments(Object... arguments) throws Throwable
invoke
от сайта вызова, который упоминает только тип Object
, и чья арность является длиной массива параметра. Определенно, выполнение продолжается, как будто следующими шагами, хотя методы, как гарантируют, не вызовут, если JVM может предсказать их эффекты.
N
. Для нулевой ссылки, N=0
. TN
из N
параметры как как TN=MethodType.genericMethodType(N)
.MH0
к необходимому типу, как MH1 = MH0.asType(TN)
. N
отдельные параметры A0, ...
. Object
ссылка. Из-за действия asType
шаг, следующие преобразования параметра применяются по мере необходимости:
Результат, возвращенный вызовом, упаковывается, если это - примитив, или вызванный к нулю, если тип возврата является пустым.
Этот вызов эквивалентен следующему коду:
MethodHandle invoker = MethodHandles.spreadInvoker(this.type(), 0); Object result = invoker.invokeExact(this, arguments);
В отличие от подписи полиморфные методы invokeExact
и invoke
, invokeWithArguments
может обычно получаться доступ через Базовый API Reflection и JNI. Это может поэтому использоваться в качестве моста между собственным или отражающим кодом и дескрипторами метода.
arguments
- параметры, чтобы передать к целиClassCastException
- если параметр не может быть преобразован ссылочным кастингомWrongMethodTypeException
- если тип цели не может быть скорректирован, чтобы взять данное число Object
параметрыThrowable
- что-либо брошенное целевым вызовом методаMethodHandles.spreadInvoker(java.lang.invoke.MethodType, int)
public Object invokeWithArguments(List<?> arguments) throws Throwable
invoke
от сайта вызова, который упоминает только тип Object
, и чья арность является длиной массива параметра. Этот метод также эквивалентен следующему коду:
invokeWithArguments
(arguments.toArray())
arguments
- параметры, чтобы передать к целиNullPointerException
- если arguments
нулевая ссылкаClassCastException
- если параметр не может быть преобразован ссылочным кастингомWrongMethodTypeException
- если тип цели не может быть скорректирован, чтобы взять данное число Object
параметрыThrowable
- что-либо брошенное целевым вызовом методаpublic MethodHandle asType(MethodType newType)
Если исходный тип и новый тип равны, возвраты this
.
Новый дескриптор метода, когда вызвано, выполнит следующие шаги:
Этот метод обеспечивает решающее поведенческое различие между invokeExact
и простой, неточный invoke
. Эти два метода выполняют те же самые шаги, когда дескриптор типа вызывающей стороны точно м. atches вызываемый, но когда типы отличаются, плоскость invoke
также вызовы asType
(или некоторый внутренний эквивалент), чтобы подойти типы вызывающей стороны и вызываемого.
Если текущий метод является переменным преобразованием списка параметров дескриптора метода арности, может включить преобразование и набор нескольких параметров в массив, как описано в другом месте. В любом случае все преобразования применяются попарно, что означает, что каждое значение аргумента или возвращаемое значение преобразовываются точно в одно значение аргумента или возвращаемое значение (или никакое возвращаемое значение). Примененные преобразования определяются, консультируясь соответствующие компонентные типы старых и новых типов дескриптора метода.
Позвольте T0 и T1 быть соответствующими новыми и старыми типами параметра, или старыми и новыми типами возврата. Определенно, для некоторых допустимых индексируют i
, позвольте T0=newType.parameterType(i)
и T1=this.type().parameterType(i)
. Или иначе, идя другим путем для возвращаемых значений, позвольте T0=this.type().returnType()
и T1=newType.returnType()
. Если типы являются тем же самым, новый дескриптор метода не производит изменения в соответствующем параметре или возвращаемом значении (если любой). Иначе, одно из следующих преобразований применяется если возможный:
java.lang.reflect.Method.invoke
.) У преобразования распаковывания должна быть возможность успеха, что означает, что, если T0 не является самостоятельно оберткой class, там должен существовать по крайней мере одна обертка ТВТ class, который является подтипом T0 и чье распакованное примитивное значение может быть расширено до T1. Преобразование дескриптора метода не может быть сделано, если кто-либо из необходимых попарных преобразований не может быть сделано.
Во времени выполнения преобразования, которым применяются к, ссылочные параметры или возвращаемые значения могут потребовать дополнительных проверок на этапе выполнения, которые могут перестать работать. Работа распаковывания может перестать работать, потому что исходная ссылка является нулем, вызывая a NullPointerException
. Работа распаковывания или ссылочный бросок могут также перестать работать на ссылке на объект неправильного типа, вызывая a ClassCastException
. Хотя работа распаковывания может принять несколько видов оберток, если ни один не доступен, a ClassCastException
будет брошен.
newType
- ожидаемый тип нового дескриптора методаthis
после выполнения любых необходимых преобразований параметра, и устраивает любые необходимые преобразования возвращаемого значенияNullPointerException
- если newType
нулевая ссылкаWrongMethodTypeException
- если преобразование не может быть сделаноMethodHandles.explicitCastArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)
public MethodHandle asSpreader(Class<?> arrayType, int arrayLength)
arrayLength
параметры типа цели заменяются единственным параметром массива типа arrayType
. Если тип элемента массива отличается от какого-либо из соответствующих типов параметра на исходной цели, исходная цель адаптируется, чтобы взять элементы массива непосредственно, как будто звонком asType
.
Когда вызвано, адаптер заменяет запаздывающий параметр массива элементами массива, каждый как его собственный параметр цели. (Порядок параметров сохраняется.) Они преобразовываются попарно, бросая и/или распаковывая к типам запаздывающих параметров цели. Наконец цель вызывают. Что цель в конечном счете возвраты возвращается неизменная адаптером.
Прежде, чем вызвать цель, адаптер проверяет, что массив содержит достаточно точно элементы, чтобы обеспечить корректное количество параметра для целевого дескриптора метода. (Массив может также быть нулем, когда нулевые элементы требуются.)
Вот некоторые простые примеры распространяющих массив дескрипторов метода:
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" })); // 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()));
arrayType
- обычно Object[]
, тип параметра массива, из которого можно извлечь параметры распространенияarrayLength
- число параметров, чтобы распространиться от входящего параметра массиваNullPointerException
- если arrayType
нулевая ссылкаIllegalArgumentException
- если arrayType
не тип массиваIllegalArgumentException
- если цель не имеет, по крайней мере, arrayLength
типы параметра, или если arrayLength
отрицательноWrongMethodTypeException
- если подразумеваемое asType
вызовите сбоиasCollector(java.lang.Class<?>, int)
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));
arrayType
- часто Object[]
, тип параметра массива, который соберет параметрыarrayLength
- число параметров, чтобы собраться в новый параметр массиваNullPointerException
- если arrayType
нулевая ссылкаIllegalArgumentException
- если arrayType
не тип массива или arrayType
не присваиваемо этому дескриптору метода запаздывание типа параметра, или arrayLength
не юридический размер массиваWrongMethodTypeException
- если подразумеваемое asType
вызовите сбоиasSpreader(java.lang.Class<?>, int)
, asVarargsCollector(java.lang.Class<?>)
public MethodHandle asVarargsCollector(Class<?> arrayType)
Тип и поведение адаптера будут тем же самым как типом и поведением цели, за исключением того, что бесспорный invoke
и asType
запросы могут привести к запаздывающим позиционным параметрам, собираемым в запаздывание цели параметра. Кроме того, последний тип параметра адаптера будет arrayType
, даже если у цели есть различный последний тип параметра.
Это преобразование может возвратиться this
если дескриптор метода уже имеет переменную арность, и ее запаздывание типа параметра идентично arrayType
.
Когда вызвано с invokeExact
, адаптер вызывает цель без изменений параметра. (Отметьте: Это поведение отличается от фиксированного коллектора арности, так как оно принимает целый массив неопределенной длины, а не постоянное число параметров.)
Когда вызвано с простым, неточным invoke
, если тип вызывающей стороны является тем же самым как адаптером, адаптер вызывает цель как с invokeExact
. (Это - нормальное поведение для invoke
когда типы соответствуют.)
Иначе, если вызывающая сторона и арность адаптера являются тем же самым, и запаздывающий тип параметра вызывающей стороны является ссылочным типом, идентичным или присваиваемый запаздывающему типу параметра адаптера, параметры и возвращаемые значения преобразовываются попарно, как будто asType
на фиксированном дескрипторе метода арности.
Иначе, арность отличается, или запаздывание адаптера типа параметра не присваиваемо от соответствующего типа вызывающей стороны. В этом случае адаптер заменяет все запаздывающие параметры от исходной запаздывающей позиции параметра вперед новым массивом типа arrayType
, чьи элементы включают (чтобы) замененные параметры.
Тип вызывающей стороны должен обеспечивать как наименьшее количество достаточно многие параметры, и корректного типа, удовлетворять требование цели для позиционных параметров перед запаздывающим параметром массива. Таким образом вызывающая сторона должна предоставить, как минимум, N-1
параметры, где N
арность цели. Кроме того, там должен существовать преобразования от входящих параметров до параметров цели. Как с другим использованием плоскости invoke
, если эти основные требования не выполняются, a WrongMethodTypeException
может быть брошен.
Во всех случаях, что цель в конечном счете возвраты возвращается неизменная адаптером.
В заключительном случае это точно, как будто целевой дескриптор метода был временно адаптирован с фиксированным коллектором арности к арности, требуемой типом вызывающей стороны. (Как с asCollector
, если длина массива является нулем, совместно используемая константа может использоваться вместо нового массива. Если подразумеваемый звонок asCollector
бросил бы IllegalArgumentException
или WrongMethodTypeException
, звонок в переменный адаптер арности должен бросить WrongMethodTypeException
.)
Поведение asType
также специализируется для переменных адаптеров арности, чтобы поддержать инвариант то простое, неточное invoke
всегда эквивалентно asType
вызовите, чтобы скорректировать целевой тип, сопровождаемый invokeExact
. Поэтому, переменный адаптер арности отвечает на asType
запрос, создавая фиксированный коллектор арности, если и только если адаптер и требуемый тип отличаются или по арности или по запаздывающему типу параметра. У получающегося фиксированного коллектора арности есть свой тип, далее скорректированный (в случае необходимости) к требуемому типу попарным преобразованием, как будто другим приложением asType
.
Когда дескриптор метода получается, выполняясь ldc
инструкция a 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
нулевая ссылкаIllegalArgumentException
- если arrayType
не тип массива или arrayType
не присваиваемо этому дескриптору метода запаздывание типа параметраasCollector(java.lang.Class<?>, int)
, isVarargsCollector()
, asFixedArity()
public boolean isVarargsCollector()
ldc
инструкция a CONSTANT_MethodHandle
который решает к переменному методу Java арности или конструктору invoke
вызовыasVarargsCollector(java.lang.Class<?>)
, asFixedArity()
public MethodHandle asFixedArity()
Если текущий дескриптор метода не имеет переменной арности, текущий дескриптор метода возвращается. Это - истина, даже если текущий дескриптор метода не мог бы быть допустимым вводом к asVarargsCollector
.
Иначе, у получающегося дескриптора метода фиксированной арности есть тот же самый тип и поведение текущего дескриптора метода, за исключением того, что isVarargsCollector
будет ложь. Дескриптор метода фиксированной арности может (или не может) быть предыдущим параметром 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()
public MethodHandle bindTo(Object x)
x
к первому параметру дескриптора метода, не вызывая это. Новый дескриптор метода адаптируется, как его цель, текущий дескриптор метода, связывая это с данным параметром. Тип связанного дескриптора будет тем же самым как типом цели, за исключением того, что будет опущен единственный ведущий ссылочный параметр. Когда вызвано, связанный дескриптор вставляет данное значение x
как новый ведущий параметр цели. Другие параметры также передают неизменные. Что цель в конечном счете возвраты возвращается неизменная связанным дескриптором.
Ссылка x
должно быть конвертируемым к первому типу параметра цели.
(Отметьте: дескрипторы метода Because являются неизменными, целевой дескриптор метода сохраняет свой исходный тип и поведение.)
x
- значение, чтобы связать с первым параметром целиIllegalArgumentException
- если у цели нет ведущего типа параметра, который является ссылочным типомClassCastException
- если x
не может быть преобразован в ведущий тип параметра целиMethodHandles.insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...)
public String toString()
"MethodHandle"
и окончание строковым представлением типа дескриптора метода. Другими словами этот метод возвращает строку, равную значению: "MethodHandle" + type().toString()
(Отметьте: Будущие выпуски этого API могут добавить дополнительную информацию к строковому представлению. Поэтому, существующий синтаксис не должен быть проанализирован приложениями.)
Для дальнейшей ссылки API и документации разработчика, см. Java Документация SE. Та документация содержит более подробные, предназначенные разработчиком описания, с концептуальными краткими обзорами, определениями сроков, обходных решений, и рабочих примеров кода.
Авторское право © 1993, 2013, Oracle и/или его филиалы. Все права защищены.
Проект сборка-b92