Spec-Zone.ru › OpenJDK 8

Класс MethodHandles.Lookup

  • java.lang.Object
    • java.lang.invoke.MethodHandles.Lookup
Вложенный класс:
MethodHandles

public static final class MethodHandles.Lookup
extends Object

Объект поиска — это фабрика для создания обработчиков методов, когда для создания требуется проверка доступа. Обработчики методов не выполняют проверки доступа при вызове, а только при создании. Поэтому ограничения доступа к обработчику методов должны быть применены при его создании. Класс вызывающего объекта, по отношению к которому применяются эти ограничения, известен как класс поиска.

Класс поиска, которому необходимо создать обработчики методов, вызовет MethodHandles.lookup, чтобы создать фабрику для себя. При создании объекта фабрики Lookup, идентификатор класса поиска определяется и безопасно хранится в объекте Lookup. Затем класс поиска (или его делегаты) могут использовать методы фабрики объекта Lookup для создания обработчиков методов для членов, проверенных на доступ. Это включает все методы, конструкторы и поля, разрешенные для класса поиска, даже приватные.

Методы фабрики поиска

Методы фабрики объекта Lookup соответствуют всем основным случаям использования методов, конструкторов и полей. Каждый обработчик метода, созданный методом фабрики, функционально эквивалентен определённому поведению байткода. (Поведение байткода описано в разделе 5.4.3.5 спецификации Java Virtual Machine.) Ниже приведён сводный обзор соответствия между этими методами фабрики и поведением получаемых обработчиков методов:
Выражение поиска Член Поведение байткода
lookup.findGetter(C.class,"f",FT.class) FT f; (T) this.f;
lookup.findStaticGetter(C.class,"f",FT.class) static
FT f;
(T) C.f;
lookup.findSetter(C.class,"f",FT.class) FT f; this.f = x;
lookup.findStaticSetter(C.class,"f",FT.class) static
FT f;
C.f = arg;
lookup.findVirtual(C.class,"m",MT) T m(A*); (T) this.m(arg*);
lookup.findStatic(C.class,"m",MT) static
T m(A*);
(T) C.m(arg*);
lookup.findSpecial(C.class,"m",MT,this.class) T m(A*); (T) super.m(arg*);
lookup.findConstructor(C.class,MT) C(A*); new C(arg*);
lookup.unreflectGetter(aField) (static)?
FT f;
(FT) aField.get(thisOrNull);
lookup.unreflectSetter(aField) (static)?
FT f;
aField.set(thisOrNull, arg);
lookup.unreflect(aMethod) (static)?
T m(A*);
(T) aMethod.invoke(thisOrNull, arg*);
lookup.unreflectConstructor(aConstructor) C(A*); (C) aConstructor.newInstance(arg*);
lookup.unreflect(aMethod) (static)?
T m(A*);
(T) aMethod.invoke(thisOrNull, arg*);
Здесь тип C — это класс или интерфейс, для которого ищется член, документированный как параметр с именем refc в методах поиска. Тип метода MT составлен из возвращаемого типа T и последовательности типов аргументов A*. Конструктор также имеет последовательность типов аргументов A* и считается возвращающим новый созданный объект типа C. И MT, и тип поля FT документированы как параметр с именем type. Формальный параметр this обозначает ссылку на самого себя типа C; если он присутствует, он всегда является ведущим аргументом вызова обработчика метода. (В случае некоторых protected членов, this может быть ограничен по типу классом поиска; см. ниже.) Имя arg обозначает все остальные аргументы обработчика метода. В примерах кода для API ядра отражения имя thisOrNull обозначает нулевую ссылку, если доступный метод или поле статические, и this в противном случае. Имена aMethod, aField, и aConstructor обозначают рефлексивные объекты, соответствующие заданным членам.

В случаях, когда заданный член имеет переменную арность (т.е. метод или конструктор), возвращаемый обработчик метода также будет иметь переменную арность. Во всех остальных случаях возвращаемый обработчик метода будет иметь фиксированную арность.

Обсуждение: Эквивалентность обработчиков методов, полученных в результате поиска, и соответствующих членам класса и поведениям байткода может нарушаться несколькими способами:

  • Если C не доступен символически из загрузчика класса поиска, поиск всё же может быть успешным, даже когда нет эквивалентного выражения Java или байткодовой константы.
  • Аналогично, если T или MT не доступен символически из загрузчика класса поиска, поиск всё же может быть успешным. Например, поиск MethodHandle.invokeExact и MethodHandle.invoke всегда будет успешным, независимо от запрошенного типа.
  • Если установлен менеджер безопасности, он может запретить поиск по различным причинам (см. ниже). В отличие от этого, инструкция ldc по константе CONSTANT_MethodHandle не подвержена проверкам менеджера безопасности.
  • Если искомый метод имеет очень большую арность, создание обработчика метода может завершиться ошибкой из-за того, что тип обработчика метода имеет слишком много параметров.

Проверка доступа

Проверки доступа применяются в методах фабрики Lookup, когда создаётся обработчик метода. Это ключевое отличие от API ядра отражения, поскольку java.lang.reflect.Method.invoke выполняет проверку доступа для каждого вызывающего объекта при каждом вызове.

Все проверки доступа начинаются с объекта Lookup, который сравнивает записанный класс поиска со всеми запросами на создание обработчиков методов. Один объект Lookup может быть использован для создания любого количества обработчиков методов, проверенных на доступ, все проверенные для одного класса поиска.

Объект Lookup может быть использован совместно с другим надёжным кодом, например, с метаобъектным протоколом. Общий объект Lookup делегирует возможность создания обработчиков методов для приватных членов класса поиска. Даже если привилегированный код использует объект Lookup, проверка доступа ограничена привилегиями исходного класса поиска.

Поиск может завершиться ошибкой, потому что содержащий класс недоступен для класса поиска, или потому что искомый член класса отсутствует, или потому что искомый член класса недоступен для класса поиска, или потому что объект поиска недостаточно надёжен для доступа к члену. В любом из этих случаев будет выброшено исключение ReflectiveOperationException при попытке поиска. Точный класс будет одним из следующих:

  • NoSuchMethodException — если запрашиваемый метод не существует
  • NoSuchFieldException — если запрашиваемое поле не существует
  • IllegalAccessException — если член существует, но проверка доступа завершается неудачно

В общем случае условия, при которых обработчик метода может быть найден для метода M, не более жёсткие, чем условия, при которых класс поиска мог бы скомпилировать, проверить и разрешить вызов M. Где JVM выбросит исключения, такие как NoSuchMethodError, поиск обработчика метода, как правило, выбросит соответствующее проверяемое исключение, такое как NoSuchMethodException. И эффект вызова обработчика метода, полученного в результате поиска, точно эквивалентен выполнению скомпилированного, проверенного и разрешенного вызова M. То же самое относится к полям и конструкторам.

Обсуждение: Проверки доступа применяются только к именованным и рефлективным методам, конструкторам и полям. Другие методы создания обработчиков методов, такие как MethodHandle.asType, не требуют проверок доступа и используются независимо от любого объекта Lookup.

Если требуемый член является protected, применяются обычные правила JVM, включая требование, что класс поиска должен быть либо в том же пакете, что и требуемый член, либо должен наследоваться от него. (См. спецификацию Java Virtual Machine, разделы 4.9.2, 5.4.3.5 и 6.4.) Кроме того, если требуемый член — это нестатическое поле или метод в другом пакете, возвращаемый обработчик метода может быть применён только к объектам класса поиска или одного из его подклассов. Это требование обеспечивается сужением типа ведущего параметра this с C (который обязательно будет суперклассом класса поиска) до самого класса поиска.

JVM накладывает аналогичное требование на инструкцию invokespecial, что аргумент получателя должен соответствовать как разрешённому методу, так и текущему классу. Опять же, это требование обеспечивается сужением типа ведущего параметра возвращаемого обработчика метода.

JVM представляет конструкторы и блоки статической инициализации как внутренние методы со специальными именами ("<init>" и "<clinit>"). Внутренний синтаксис инструкций вызова позволяет им ссылаться на такие внутренние методы так, как будто они являются обычными методами, но верификатор байткода JVM отклоняет их. Поиск такого внутреннего метода приведет к NoSuchMethodException.

В некоторых случаях доступ между вложенными классами обеспечивается компилятором Java, создающим оберточную функцию для доступа к закрытому методу другого класса в том же верхнем уровне объявления. Например, вложенный класс C.D может получить доступ к закрытым членам других связанных классов, таких как C, C.D.E или C.B, но компилятор Java может потребовать создания оберточных функций в этих связанных классах. В таких случаях объект Lookup в C.E не сможет получить доступ к этим закрытым членам. Рабочим решением этой проблемы является метод Lookup.in, который может преобразовать поиск по C.E в поиск по любому из этих других классов без специального повышения привилегий.

Доступ, разрешённый данному объекту поиска, может быть ограничен, согласно его набору lookupModes, подмножеством членов, обычно доступных классу поиска. Например, метод publicLookup создаёт объект поиска, которому разрешено только обращаться к общедоступным членам в общедоступных классах. Метод lookup, учитывающий вызывающего, создаёт объект поиска с полными возможностями относительно вызывающего класса, чтобы эмулировать все поддерживаемые поведения байт-кода. Также метод Lookup.in может создать объект поиска с меньшим количеством режимов доступа, чем исходный объект поиска.

Обсуждение доступа к закрытым членам: Мы говорим, что поиск имеет доступ к закрытым членам, если его режимы поиска включают возможность доступа к private членам. Как документировано в соответствующих методах в другом месте, только поиски с доступом к закрытым членам обладают следующими возможностями:

  • доступ к закрытым полям, методам и конструкторам класса поиска
  • создание обработчиков методов, которые вызывают методы, учитывающие вызывающего, такие как Class.forName
  • создание обработчиков методов, которые emulate invokespecial инструкции
  • избегание проверок доступа к пакетам для классов, доступных классу поиска
  • создание delegated lookup objects, которые имеют доступ к закрытым членам других классов в том же пакете

Каждое из этих разрешений является следствием того, что объект поиска с доступом к закрытым членам может быть безопасно прослежен до исходного класса, чьи поведения байт-кода и разрешения доступа языка Java могут быть надёжно определены и эмулированы обработчиками методов.

Взаимодействие с менеджером безопасности

Хотя инструкции байт-кода могут ссылаться только на классы в связанном загрузчике классов, этот API может искать методы в любом классе, если доступен ссылка на его Class объект. Такие межзагрузчиковые ссылки также возможны с помощью API ядра рефлексии и невозможны для инструкций байт-кода, таких как invokestatic или getfield. Для проверки таких межзагрузчиковых ссылок существует API менеджера безопасности. Эти проверки применимы как к API MethodHandles.Lookup, так и к API ядра рефлексии (как в Class).

Если менеджер безопасности присутствует, поиски членов подвергаются дополнительным проверкам. Выполняется от одного до трёх вызовов менеджеру безопасности. Любой из этих вызовов может отказаться от доступа, бросив исключение SecurityException. Определим smgr как менеджер безопасности, lookc как класс поиска текущего объекта поиска, refc как содержащий класс, в котором ищется член, и defc как класс, в котором член фактически определён. Значение lookc определено как отсутствующий, если текущий объект поиска не имеет доступа к закрытым членам. Вызовы выполняются в соответствии со следующими правилами:

  • Шаг 1: Если lookc отсутствует или его загрузчик классов не совпадает и не является предком загрузчика классов refc, то вызывается smgr.checkPackageAccess(refcPkg), где refcPkg — пакет refc.
  • Шаг 2: Если полученный член не является общедоступным и lookc отсутствует, то вызывается smgr.checkPermission с RuntimePermission("accessDeclaredMembers").
  • Шаг 3: Если полученный член не является общедоступным, lookc отсутствует, а defc и refc различны, то вызывается smgr.checkPackageAccess(defcPkg), где defcPkg — пакет defc.
Проверки безопасности выполняются после прохождения других проверок доступа. Следовательно, вышеуказанные правила предполагают член, который является общедоступным или к которому есть доступ из класса поиска, имеющего права на доступ к нему.

Методы, учитывающие вызывающего

Небольшое количество методов Java имеет специальное свойство, называемое чувствительностью к вызывающему. Метод, учитывающий вызывающего, может вести себя по-разному в зависимости от идентификатора его непосредственного вызывающего.

Если запрашивается обработчик метода для метода, учитывающего вызывающего, применяются общие правила для поведений байт-кода, но они учитывают класс поиска особым образом. Результирующий обработчик методов ведёт себя так, как будто он был вызван инструкцией, содержащейся в классе поиска, чтобы метод, учитывающий вызывающего, обнаружил класс поиска. (В отличие от этого, вызывающий обработчик метода игнорируется.) Таким образом, в случае методов, учитывающих вызывающего, разные классы поиска могут давать обработчики методов с различным поведением.

В случаях, когда объект поиска является publicLookup() или другим объектом поиска без доступа к закрытым членам, класс поиска игнорируется. В таких случаях обработчик метода, учитывающий вызывающего, создать нельзя, доступ запрещён, и поиск завершается с IllegalAccessException.

Обсуждение: Например, метод Class.forName(x), учитывающий вызывающего, может возвращать разные классы или выбрасывать разные исключения в зависимости от загрузчика классов класса, который его вызывает. Публичный поиск по Class.forName потерпит неудачу, потому что нет разумного способа определить его поведение байт-кода.

Если приложение кэширует обработчики методов для широкого совместного использования, оно должно использовать publicLookup() для их создания. Если есть поиск по Class.forName, он потерпит неудачу, и приложение должно принять соответствующие меры в этом случае. Возможно, что более поздний поиск, возможно, во время вызова метода загрузки, сможет учесть конкретную личность вызывающего, сделав метод доступным.

Функция MethodHandles.lookup учитывает вызывающего, чтобы обеспечить надёжную основу для поиска. Почти все другие методы API JSR 292 полагаются на объекты поиска для проверки запросов на доступ.

Поля

Модификатор и тип Поле и описание
static int PACKAGE

Однобитовая маска, представляющая package доступ (по умолчанию), которая может повлиять на результат lookupModes.

static int PRIVATE

Однобитовая маска, представляющая private доступ, которая может повлиять на результат lookupModes.

static int PROTECTED

Однобитовая маска, представляющая protected доступ, которая может повлиять на результат lookupModes.

static int PUBLIC

Однобитовая маска, представляющая public доступ, которая может повлиять на результат lookupModes.

Методы

Модификатор и тип Метод и описание
MethodHandle bind(Object receiver, String name, MethodType type)

Создаёт обработчик раннего связанного метода для нестатического метода.

MethodHandle findConstructor(Class<?> refc, MethodType type)

Создаёт обработчик метода, который создаёт объект и инициализирует его, используя конструктор указанного типа.

MethodHandle findGetter(Class<?> refc, String name, Class<?> type)

Создаёт обработчик метода, предоставляющий доступ для чтения к нестатическому полю.

MethodHandle findSetter(Class<?> refc, String name, Class<?> type)

Создаёт обработчик метода, предоставляющий доступ для записи к нестатическому полю.

MethodHandle findSpecial(Class<?> refc, String name, MethodType type, Class<?> specialCaller)

Создаёт обработчик раннего связанного метода для виртуального метода.

MethodHandle findStatic(Class<?> refc, String name, MethodType type)

Создаёт обработчик метода для статического метода.

MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type)

Создаёт обработчик метода, предоставляющий доступ для чтения к статическому полю.

MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type)

Создаёт обработчик метода, предоставляющий доступ для записи к статическому полю.

MethodHandle findVirtual(Class<?> refc, String name, MethodType type)

Создаёт обработчик метода для виртуального метода.

MethodHandles.Lookup in(Class<?> requestedLookupClass)

Создаёт поиск в указанном новом классе поиска.

Class<?> lookupClass()

Указывает, какой класс выполняет поиск.

int lookupModes()

Указывает, какие классы защиты доступа к членам может генерировать этот объект поиска.

MethodHandleInfo revealDirect(MethodHandle target)

Распаковывает прямой обработчик метода, созданный этим объектом поиска или аналогичным ему.

String toString()

Отображает имя класса, из которого должны производиться поиски.

MethodHandle unreflect(Method m)

Создаёт прямой обработчик метода для m, если класс поиска имеет разрешение.

MethodHandle unreflectConstructor(Constructor<?> c)

Создаёт обработчик метода для отражённого конструктора.

MethodHandle unreflectGetter(Field f)

Создаёт обработчик метода, предоставляющий доступ для чтения к отражённому полю.

MethodHandle unreflectSetter(Field f)

Создаёт обработчик метода, предоставляющий доступ для записи к отражённому полю.

MethodHandle unreflectSpecial(Method m, Class<?> specialCaller)

Создаёт обработчик метода для отражённого метода.

Методы, унаследованные от класса java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait

Поля

ОБЩЕДОСТУПНЫЕ

public static final int PUBLIC

Маска из одного бита, представляющая public доступ, которая может повлиять на результат вызова lookupModes. Значение, 0x01, совпадает со значением public бита модификатора.

См. также:
Значения константных полей

ПРИВАТНЫЕ

public static final int PRIVATE

Маска из одного бита, представляющая private доступ, которая может повлиять на результат вызова lookupModes. Значение, 0x02, совпадает со значением private бита модификатора.

См. также:
Значения константных полей

ЗАЩИЩЕННЫЕ

public static final int PROTECTED

Маска из одного бита, представляющая protected доступ, которая может повлиять на результат вызова lookupModes. Значение, 0x04, совпадает со значением protected бита модификатора.

См. также:
Значения константных полей

УПАКОВАННЫЕ

public static final int PACKAGE

Маска из одного бита, представляющая package доступ (по умолчанию), которая может повлиять на результат вызова lookupModes. Значение равно 0x08, что не соответствует никакому конкретному биту модификатора.

См. также:
Значения константных полей

Методы

lookupClass

public Class<?> lookupClass()

Указывает, какой класс выполняет поиск. Именно с этим классом производятся проверки видимости и разрешений доступа.

Класс подразумевает максимальный уровень разрешений доступа, но разрешения могут быть дополнительно ограничены маской lookupModes, которая управляет возможностью доступа к непубличным членам.

Возвращает:
класс поиска, от имени которого этот объект поиска находит члены

lookupModes

public int lookupModes()

Указывает, какие классы защиты доступа к членам может создавать этот объект поиска. Результат представляет собой битовую маску битов PUBLIC (0x01), PRIVATE (0x02), PROTECTED (0x04) и PACKAGE (0x08).

Недавно созданный объект поиска в классе вызывающего вызывающего класса имеет все возможные биты установленные, так как вызывающий класс может получить доступ ко всем своим членам. Объект поиска в новом классе поиска созданный на основе предыдущего объекта поиска может иметь некоторые биты режима, установленные в ноль. Цель этого ограничения доступа через новый объект поиска, так что он может получить доступ только к именам, которые могут быть достигнуты исходным объектом поиска, а также новым классом поиска.

Возвращает:
режимы поиска, которые ограничивают типы доступа, выполняемые этим объектом поиска

in

public MethodHandles.Lookup in(Class<?> requestedLookupClass)

Создает поиск в указанном новом классе поиска. Результирующий объект будет указывать указанный класс в качестве своего lookupClass.

Однако, полученный Lookup объект гарантированно не имеет больше возможностей доступа, чем исходный. В частности, возможности доступа могут быть потеряны следующим образом:

  • Если новый класс поиска отличается от старого, защищенные члены не будут доступны в силу наследования. (Защищенные члены могут оставаться доступными из-за совместного использования пакета.)
  • Если новый класс поиска находится в другом пакете, чем старый, защищенные и стандартные (пакетные) члены не будут доступны.
  • Если новый класс поиска не находится в том же пакете, что и старый, частные члены не будут доступны.
  • Если новый класс поиска недоступен для старого класса поиска, то ни один член, даже публичный член, не будет доступен. (Во всех остальных случаях публичные члены останутся доступными.)
Параметры:
requestedLookupClass - желаемый класс поиска для нового объекта поиска
Возвращает:
объект поиска, который указывает желаемый класс поиска
Исключения:
NullPointerException - если аргумент равен null

toString

public String toString()

Отображает имя класса, из которого должны выполняться поиски. (Имя - это то, которое возвращается методом Class.getName.) Если существуют ограничения на разрешенный доступ к этому поиску, это указывается добавлением суффикса к имени класса, состоящего из слеша и ключевого слова. Ключевое слово представляет собой самый сильный разрешенный доступ и выбирается следующим образом:

  • Если доступ не разрешен, суффикс - "/noaccess".
  • Если разрешен только публичный доступ, суффикс - "/public".
  • Если разрешены только публичный и пакетный доступ, суффикс - "/package".
  • Если разрешены только публичный, пакетный и приватный доступ, суффикс - "/private".
Если ни один из вышеперечисленных случаев не применим, разрешен полный доступ (публичный, пакетный, приватный и защищенный). В этом случае суффикс не добавляется. Это верно только для объекта, первоначально полученного из MethodHandles.lookup. Объекты, созданные с помощью Lookup.in, всегда имеют ограниченный доступ и будут отображать суффикс.

(Может показаться странным, что защищенный доступ сильнее, чем приватный. Если рассматривать отдельно от доступа к пакету, защищенный доступ теряется первым, поскольку он требует прямой связи между вызывающим и вызываемым подклассами.)

Переопределяет:
toString в классе Object
Возвращает:
строковое представление объекта.
См. также:
in(java.lang.Class<?>)

findStatic

public MethodHandle findStatic(Class<?> refc,
                               String name,
                               MethodType type)
                        throws NoSuchMethodException,
                               IllegalAccessException

Создает обработчик метода для статического метода. Тип обработчика метода будет соответствовать типу метода. (Так как статические методы не принимают получателей, дополнительный аргумент получателя не вставляется в тип обработчика метода, в отличие от findVirtual или findSpecial.) Метод и все его типы аргументов должны быть доступны объекту поиска.

Возвращаемый обработчик метода будет иметь переменную арность только в том случае, если установлен бит модификатора переменной арности метода (0x0080).

Если возвращаемый обработчик метода вызывается, класс метода будет инициализирован, если он еще не был инициализирован.

Пример:

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle MH_asList = publicLookup().findStatic(Arrays.class,
  "asList", methodType(List.class, Object[].class));
assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
Параметры:
refc - класс, из которого происходит доступ к методу
name - имя метода
type - тип метода
Возвращает:
требуемый обработчик метода
Исключения:
NoSuchMethodException - если метод не существует
IllegalAccessException - если проверка доступа завершается неудачно, или если метод не static, или если бит модификатора переменной арности метода установлен, и asVarargsCollector завершается неудачно
SecurityException - если менеджер безопасности присутствует и он отказывается предоставить доступ
NullPointerException - если какой-либо аргумент равен null

findVirtual

public MethodHandle findVirtual(Class<?> refc,
                                String name,
                                MethodType type)
                         throws NoSuchMethodException,
                                IllegalAccessException

Создает обработчик метода для виртуального метода. Тип обработчика метода будет соответствовать типу метода, с типом получателя (обычно refc) впереди. Метод и все его типы аргументов должны быть доступны объекту поиска.

При вызове обработчик будет рассматривать первый аргумент как получателя и выполнять диспетчеризацию по типу получателя, чтобы определить, какую реализацию метода следует использовать. (Действие диспетчеризации идентично тому, которое выполняется инструкцией invokevirtual или invokeinterface)

Первый аргумент будет типа refc, если класс поиска имеет полные привилегии доступа к члену. В противном случае член должен быть protected, и первый аргумент будет ограничен типом до класса поиска.

Возвращаемый обработчик метода будет иметь переменную арность только в том случае, если бит модификатора переменной арности метода (0x0080) установлен.

Из-за общей эквивалентности между инструкциями invokevirtual и обработчиками методов, созданными findVirtual, если класс MethodHandle, а строка имени invokeExact или invoke, результирующий обработчик метода эквивалентен обработчику, созданному с помощью MethodHandles.exactInvoker или MethodHandles.invoker с тем же аргументом type. Пример:

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle MH_concat = publicLookup().findVirtual(String.class,
  "concat", methodType(String.class, String.class));
MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class,
  "hashCode", methodType(int.class));
MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class,
  "hashCode", methodType(int.class));
assertEquals("xy", (String) MH_concat.invokeExact("x", "y"));
assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy"));
assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy"));
// interface method:
MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class,
  "subSequence", methodType(CharSequence.class, int.class, int.class));
assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString());
// constructor "internal method" must be accessed differently:
MethodType MT_newString = methodType(void.class); //()V for new String()
try { assertEquals("impossible", lookup()
        .findVirtual(String.class, "<init>", MT_newString));
 } catch (NoSuchMethodException ex) { } // OK
MethodHandle MH_newString = publicLookup()
  .findConstructor(String.class, MT_newString);
assertEquals("", (String) MH_newString.invokeExact());
Параметры:
refc - класс или интерфейс, из которого происходит доступ к методу
name - имя метода
type - тип метода, без аргумента получателя
Возвращает:
требуемый обработчик метода
Исключения:
NoSuchMethodException - если метод не существует
IllegalAccessException - если проверка доступа завершается неудачно, или если метод static или если бит модификатора переменной арности метода установлен, и asVarargsCollector завершается неудачно
SecurityException - если менеджер безопасности присутствует и он отказывается предоставить доступ
NullPointerException - если какой-либо аргумент равен null

findConstructor

public MethodHandle findConstructor(Class<?> refc,
                                    MethodType type)
                             throws NoSuchMethodException,
                                    IllegalAccessException

Создаёт обработчик метода, который создаёт объект и инициализирует его, используя конструктор указанного типа. Типы параметров обработчика метода будут соответствовать типам конструктора, а тип возвращаемого значения — ссылке на класс конструктора. Конструктор и все его типы аргументов должны быть доступны объекту поиска.

Запрашиваемый тип должен иметь тип возврата void. (Это согласуется с обработкой описателей типа конструктора в JVM.)

Возвращаемый обработчик метода будет иметь переменную арность тогда и только тогда, когда установлен бит модификатора переменной арности конструктора (0x0080) .

Если возвращаемый обработчик метода будет вызван, класс конструктора будет инициализирован, если он ещё не был инициализирован.

Пример:

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle MH_newArrayList = publicLookup().findConstructor(
  ArrayList.class, methodType(void.class, Collection.class));
Collection orig = Arrays.asList("x", "y");
Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig);
assert(orig != copy);
assertEquals(orig, copy);
// a variable-arity constructor:
MethodHandle MH_newProcessBuilder = publicLookup().findConstructor(
  ProcessBuilder.class, methodType(void.class, String[].class));
ProcessBuilder pb = (ProcessBuilder)
  MH_newProcessBuilder.invoke("x", "y", "z");
assertEquals("[x, y, z]", pb.command().toString());
Параметры:
refc - класс или интерфейс, из которого обращается метод
type - тип метода, без аргумента получателя и с типом возвращаемого значения void
Возвращает:
необходимый обработчик метода
Исключения:
NoSuchMethodException - если конструктор не существует
IllegalAccessException - если проверка доступа не удалась или если бит модификатора переменной арности метода установлен, и проверка asVarargsCollector не удалась
SecurityException - если присутствует менеджер безопасности, и он отказывается предоставить доступ
NullPointerException - если какой-либо аргумент равен null

findSpecial

public MethodHandle findSpecial(Class<?> refc,
                                String name,
                                MethodType type,
                                Class<?> specialCaller)
                         throws NoSuchMethodException,
                                IllegalAccessException

Создаёт обработчик метода ранней привязки для виртуального метода. Он обойдёт проверки на переопределяемые методы в получателе, как будто вызван инструкцией invokespecial из явно указанного specialCaller. Тип обработчика метода будет соответствовать типу метода с предварительно добавленным типом получателя. (Тип получателя будет specialCaller или его подтипом.) Метод и все его типы аргументов должны быть доступны объекту поиска.

Перед разрешением метода, если явно указанный класс вызывающего не идентичен классу поиска, или если у этого объекта поиска нет привилегий частного доступа, доступ не предоставляется.

Возвращаемый обработчик метода будет иметь переменную арность тогда и только тогда, когда установлен бит модификатора переменной арности метода (0x0080) .

(Примечание: внутренние методы JVM с именем "<init>" не видны этому API, даже если инструкция invokespecial может ссылаться на них в особых случаях. Используйте findConstructor для доступа к методам инициализации экземпляра безопасным способом.)

Пример:

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
static class Listie extends ArrayList {
  public String toString() { return "[wee Listie]"; }
  static Lookup lookup() { return MethodHandles.lookup(); }
}
...
// no access to constructor via invokeSpecial:
MethodHandle MH_newListie = Listie.lookup()
  .findConstructor(Listie.class, methodType(void.class));
Listie l = (Listie) MH_newListie.invokeExact();
try { assertEquals("impossible", Listie.lookup().findSpecial(
        Listie.class, "<init>", methodType(void.class), Listie.class));
 } catch (NoSuchMethodException ex) { } // OK
// access to super and self methods via invokeSpecial:
MethodHandle MH_super = Listie.lookup().findSpecial(
  ArrayList.class, "toString" , methodType(String.class), Listie.class);
MethodHandle MH_this = Listie.lookup().findSpecial(
  Listie.class, "toString" , methodType(String.class), Listie.class);
MethodHandle MH_duper = Listie.lookup().findSpecial(
  Object.class, "toString" , methodType(String.class), Listie.class);
assertEquals("[]", (String) MH_super.invokeExact(l));
assertEquals(""+l, (String) MH_this.invokeExact(l));
assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method
try { assertEquals("inaccessible", Listie.lookup().findSpecial(
        String.class, "toString", methodType(String.class), Listie.class));
 } catch (IllegalAccessException ex) { } // OK
Listie subl = new Listie() { public String toString() { return "[subclass]"; } };
assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
Параметры:
refc - класс или интерфейс, из которого обращается метод
name - имя метода (которое не должно быть "<init>")
type - тип метода без аргумента получателя
specialCaller - предполагаемый класс вызывающего, для выполнения invokespecial
Возвращает:
необходимый обработчик метода
Исключения:
NoSuchMethodException - если метод не существует
IllegalAccessException - если проверка доступа не удалась или если бит модификатора переменной арности метода установлен, и проверка asVarargsCollector не удалась
SecurityException - если присутствует менеджер безопасности, и он отказывается предоставить доступ
NullPointerException - если какой-либо аргумент равен null

findGetter

public MethodHandle findGetter(Class<?> refc,
                               String name,
                               Class<?> type)
                        throws NoSuchFieldException,
                               IllegalAccessException

Создаёт обработчик метода, предоставляющий доступ для чтения к нестатическому полю. Тип обработчика метода будет иметь тип возвращаемого значения поля. Единственный аргумент обработчика метода будет экземпляром, содержащим поле. Проверка доступа выполняется немедленно от имени класса поиска.

Параметры:
refc - класс или интерфейс, из которого обращается метод
name - имя поля
type - тип поля
Возвращает:
обработчик метода, который может загружать значения из поля
Исключения:
NoSuchFieldException - если поле не существует
IllegalAccessException - если проверка доступа не удалась, или если поле static
SecurityException - если присутствует менеджер безопасности, и он отказывается предоставить доступ
NullPointerException - если какой-либо аргумент равен null

findSetter

public MethodHandle findSetter(Class<?> refc,
                               String name,
                               Class<?> type)
                        throws NoSuchFieldException,
                               IllegalAccessException

Создаёт обработчик метода, предоставляющий доступ для записи в нестатическое поле. Тип обработчика метода будет иметь тип возврата void. Обработчик метода будет принимать два аргумента: экземпляр, содержащий поле, и значение, которое нужно сохранить. Второй аргумент будет типа значения поля. Проверка доступа выполняется немедленно от имени класса поиска.

Параметры:
refc - класс или интерфейс, из которого обращается метод
name - имя поля
type - тип поля
Возвращает:
обработчик метода, который может сохранять значения в поле
Исключения:
NoSuchFieldException - если поле не существует
IllegalAccessException - если проверка доступа не удалась, или если поле static
SecurityException - если присутствует менеджер безопасности, и он отказывается предоставить доступ
NullPointerException - если какой-либо аргумент равен null

findStaticGetter

public MethodHandle findStaticGetter(Class<?> refc,
                                     String name,
                                     Class<?> type)
                              throws NoSuchFieldException,
                                     IllegalAccessException

Создаёт обработчик метода, предоставляющий доступ для чтения к статическому полю. Тип обработчика метода будет иметь тип возврата значения поля. Обработчик метода не будет принимать аргументов. Проверка доступа выполняется немедленно от имени класса поиска.

Если возвращаемый обработчик метода вызывается, класс поля будет инициализирован, если он ещё не был инициализирован.

Параметры:
refc - класс или интерфейс, из которого обращается метод
name - имя поля
type - тип поля
Возвращает:
обработчик метода, который может загружать значения из поля
Исключения:
NoSuchFieldException - если поле не существует
IllegalAccessException - если проверка доступа не удалась, или если поле не static
SecurityException - если присутствует менеджер безопасности, и он отказывается предоставить доступ
NullPointerException - если какой-либо аргумент равен null

findStaticSetter

public MethodHandle findStaticSetter(Class<?> refc,
                                     String name,
                                     Class<?> type)
                              throws NoSuchFieldException,
                                     IllegalAccessException

Создаёт обработчик метода, предоставляющий доступ для записи в статическое поле. Тип обработчика метода будет иметь тип возврата void. Обработчик метода будет принимать один аргумент типа значения поля — значение, которое нужно сохранить. Проверка доступа выполняется немедленно от имени класса поиска.

Если возвращаемый обработчик метода вызывается, класс поля будет инициализирован, если он ещё не был инициализирован.

Параметры:
refc - класс или интерфейс, из которого обращается метод
name - имя поля
type - тип поля
Возвращает:
обработчик метода, который может сохранять значения в поле
Исключения:
NoSuchFieldException - если поле не существует
IllegalAccessException - если проверка доступа не удалась, или если поле не static
SecurityException - если присутствует менеджер безопасности, и он отказывается предоставить доступ
NullPointerException - если какой-либо аргумент равен null

bind

public MethodHandle bind(Object receiver,
                         String name,
                         MethodType type)
                  throws NoSuchMethodException,
                         IllegalAccessException

Создаёт обработчик метода ранней привязки для нестатического метода. Получатель должен иметь супертип defc, в котором метод с заданным именем и типом доступен классу поиска. Метод и все его типы аргументов должны быть доступны объекту поиска. Тип обработчика метода будет соответствовать типу метода без вставки дополнительного параметра получателя. Указанный получатель будет привязан к обработчику метода, так что каждый вызов обработчика метода будет вызывать запрашиваемый метод на данном получателе.

Возвращаемый обработчик метода будет иметь переменную арность тогда и только тогда, когда бит модификатора переменной арности метода (0x0080) установлен и аргумент массива с последующим расположением не является единственным аргументом. (Если аргумент массива с последующим расположением является единственным аргументом, заданное значение получателя будет привязано к нему.)

Это эквивалентно следующему коду:

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle mh0 = lookup().findVirtual(defc, name, type);
MethodHandle mh1 = mh0.bindTo(receiver);
MethodType mt1 = mh1.type();
if (mh0.isVarargsCollector())
  mh1 = mh1.asVarargsCollector(mt1.parameterType(mt1.parameterCount()-1));
return mh1;
где defc — это receiver.getClass() или супертип этого класса, в котором запрашиваемый метод доступен классу поиска. (Обратите внимание, что bindTo не сохраняет переменную арность.)
Параметры:
receiver - объект, из которого обращается метод
name - имя метода
type - тип метода без аргумента получателя
Возвращает:
необходимый обработчик метода
Исключения:
NoSuchMethodException - если метод не существует
IllegalAccessException - если проверка доступа не удалась или если бит модификатора переменной арности метода установлен, и проверка asVarargsCollector не удалась
SecurityException - если присутствует менеджер безопасности, и он отказывается предоставить доступ
NullPointerException - если какой-либо аргумент равен null
См. также:
MethodHandle.bindTo(java.lang.Object), findVirtual(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType)

unreflect

public MethodHandle unreflect(Method m)
                       throws IllegalAccessException

Создаёт прямое обращение к методу к m, если у класса поиска есть разрешение. Если m не статический, аргумент получателя обрабатывается как начальный аргумент. Если m виртуальный, переопределение учитывается при каждом вызове. В отличие от API отражения ядра, исключения не обертываются. Тип обработчика метода будет таким же, как у метода, с типом получателя в префиксе (но только если он не статический). Если флаг accessible метода m не установлен, проверка доступа выполняется немедленно от имени класса поиска. Если m не общедоступен, не следует передавать полученный обработчик недоверенным сторонам.

Возвращаемый обработчик метода будет иметь переменную арность, если и только если бит модификатора переменной арности метода (0x0080) установлен.

Если m статический, и если возвращаемый обработчик метода вызывается, класс метода будет инициализирован, если он ещё не был инициализирован.

Параметры:
m - отражённый метод
Возвращает:
обработчик метода, который может вызвать отражённый метод
Исключения:
IllegalAccessException - если проверка доступа завершилась неудачно или если бит модификатора переменной арности метода установлен, и asVarargsCollector завершился неудачно
NullPointerException - если аргумент равен null

unreflectSpecial

public MethodHandle unreflectSpecial(Method m,
                                     Class<?> specialCaller)
                              throws IllegalAccessException

Создаёт обработчик метода для отражённого метода. Он обойдёт проверки переопределённых методов получателя, как если бы он был вызван из invokespecial инструкции внутри явно указанного specialCaller. Тип обработчика метода будет таким же, как у метода, с соответствующим ограниченным типом получателя в префиксе. (Тип получателя будет specialCaller или подтипом.) Если флаг accessible метода не установлен, проверка доступа выполняется немедленно от имени класса поиска, как если бы invokespecial инструкция была связана.

Перед разрешением метода, если явно указанный класс вызывающей стороны не идентичен классу поиска, или если у этого объекта поиска нет привилегий частного доступа, доступ отклоняется.

Возвращаемый обработчик метода будет иметь переменную арность, если и только если бит модификатора переменной арности метода (0x0080) установлен.

Параметры:
m - отражённый метод
specialCaller - класс, номинально вызывающий метод
Возвращает:
обработчик метода, который может вызвать отражённый метод
Исключения:
IllegalAccessException - если проверка доступа завершилась неудачно или если бит модификатора переменной арности метода установлен, и asVarargsCollector завершился неудачно
NullPointerException - если любой аргумент равен null

unreflectConstructor

public MethodHandle unreflectConstructor(Constructor<?> c)
                                  throws IllegalAccessException

Создаёт обработчик метода для отражённого конструктора. Тип обработчика метода будет таким же, как у конструктора, с типом возвращаемого значения, изменённым на класс объявления. Обработчик метода выполнит операцию newInstance, создав новый экземпляр класса конструктора на аргументах, переданных обработчику метода.

Если флаг accessible конструктора не установлен, проверка доступа выполняется немедленно от имени класса поиска.

Возвращаемый обработчик метода будет иметь переменную арность, если и только если бит модификатора переменной арности конструктора (0x0080) установлен.

Если возвращаемый обработчик метода вызывается, класс конструктора будет инициализирован, если он ещё не был инициализирован.

Параметры:
c - отражённый конструктор
Возвращает:
обработчик метода, который может вызвать отражённый конструктор
Исключения:
IllegalAccessException - если проверка доступа завершилась неудачно или если бит модификатора переменной арности метода установлен, и asVarargsCollector завершился неудачно
NullPointerException - если аргумент равен null

unreflectGetter

public MethodHandle unreflectGetter(Field f)
                             throws IllegalAccessException

Создаёт обработчик метода, предоставляющий чтение доступа к отражённому полю. Тип обработчика метода будет иметь тип значения поля в качестве типа возвращаемого значения. Если поле статическое, обработчик метода не будет принимать аргументы. В противном случае его единственный аргумент будет представлять экземпляр, содержащий поле. Если флаг accessible поля не установлен, проверка доступа выполняется немедленно от имени класса поиска.

Если поле статическое, и если возвращаемый обработчик метода вызывается, класс поля будет инициализирован, если он ещё не был инициализирован.

Параметры:
f - отражённое поле
Возвращает:
обработчик метода, который может загружать значения из отражённого поля
Исключения:
IllegalAccessException - если проверка доступа завершилась неудачно
NullPointerException - если аргумент равен null

unreflectSetter

public MethodHandle unreflectSetter(Field f)
                             throws IllegalAccessException

Создаёт обработчик метода, предоставляющий запись доступа к отражённому полю. Тип обработчика метода будет иметь тип void в качестве типа возвращаемого значения. Если поле статическое, обработчик метода будет принимать один аргумент, типа значения поля — значение, которое нужно сохранить. В противном случае два аргумента будут экземпляром, содержащим поле, и значением, которое нужно сохранить. Если флаг accessible поля не установлен, проверка доступа выполняется немедленно от имени класса поиска.

Если поле статическое, и если возвращаемый обработчик метода вызывается, класс поля будет инициализирован, если он ещё не был инициализирован.

Параметры:
f - отражённое поле
Возвращает:
обработчик метода, который может сохранять значения в отражённое поле
Исключения:
IllegalAccessException - если проверка доступа завершилась неудачно
NullPointerException - если аргумент равен null

revealDirect

public MethodHandleInfo revealDirect(MethodHandle target)

Раскрывает прямое обращение к методу, созданный этим объектом поиска или аналогичным. Проверяются безопасность и доступ для обеспечения возможности этого объекта поиска воссоздания целевого обработчика метода. Это означает, что раскрытие может завершиться неудачей, если цель — прямой обработчик метода, но был создан несвязанным объектом поиска. Это может произойти, если обработчик метода зависит от вызывающей стороны и был создан объектом поиска для другого класса.

Параметры:
target - прямое обращение к методу для раскрытия в компоненты символической ссылки
Возвращает:
символическая ссылка, которая может быть использована для воссоздания этого обработчика метода с помощью этого объекта поиска
Исключения:
SecurityException - если менеджер безопасности присутствует и он отклоняет доступ
IllegalArgumentException - если цель не является прямым обращением к методу или если проверка доступа завершилась неудачно
NullPointerException - если цель null
С момента:
1.8
См. также:
MethodHandleInfo

© 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.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API