|
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