Spec-Zone.ru › OpenJDK 17

Класс 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

Методы фабрики объекта 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;
(FT) 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.unreflectSpecial(aMethod,this.class) T m(A*); (T) super.m(arg*);
lookup.findClass("C") class C { ... } C.class;
Здесь тип C — это класс или интерфейс, в котором ищется член, документированный как параметр с именем refc в методах поиска. Тип метода MT состоит из возвращаемого типа T и последовательности типов аргументов A*. Конструктор также имеет последовательность типов аргументов A* и считается возвращающим новый созданный объект типа C. И MT, и тип поля FT документированы как параметр с именем type. Формальный параметр this представляет собой самоссылку типа C; если он присутствует, он всегда является ведущим аргументом вызова обработчика методов. (В случае некоторых protected членов this может быть ограничен типом до класса поиска; см. ниже.) Название arg обозначает все остальные аргументы обработчика методов. В примерах кода для API ядра рефлексии имя thisOrNull обозначает нулевую ссылку, если доступный метод или поле статическое, и this в противном случае. Имена aMethod, aField, и aConstructor обозначают рефлективные объекты, соответствующие заданным членам, объявленным в типе C.

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

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

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

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

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

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

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

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

Поиск может завершиться неудачей, потому что содержащий класс недоступен для класса поиска, или потому что нужный член класса отсутствует, или потому что нужный член класса недоступен для класса поиска, или потому что объект поиска недостаточно доверен для доступа к члену. В случае функции установки поля на поле final, принуждение к финальности рассматривается как своего рода контроль доступа, и поиск завершится неудачей, за исключением особых случаев Lookup.unreflectSetter. В любом из этих случаев будет брошено исключение 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, требуя, чтобы аргумент получателя соответствовал как разрешенному методу, так и текущему классу. Опять же, это требование обеспечивается сужением типа ведущего параметра до полученного дескриптора метода. (См. спецификацию Java Virtual Machine, раздел 4.10.1.9.)

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

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

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

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

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

Аналогично, поиск с модульным доступом гарантирует, что исходный создатель поиска был членом того же модуля, что и класс поиска.

Частный и модульный доступ определяются независимо; поиск может иметь один или оба, или ни одного. Поиск, который обладает обоими режимами доступа, называется обладающим полным доступом с привилегиями.

Поиск с исходным доступом гарантирует, что этот поиск создан исходным классом поиска и вызываемым bootstrap-методом JVM. Такой поиск с исходным доступом также имеет частный и модульный доступ, который имеет следующие дополнительные возможности:

  • создание дескрипторов методов, которые вызывают методы, чувствительные к вызывающему элементу, такие как Class.forName
  • получение данных класса, связанных с классом поиска

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

Межмодульные поиски

Когда класс поиска в одном модуле M1 обращается к классу в другом модуле M2, выполняется дополнительная проверка доступа, помимо битов режима доступа. Lookup с режимом PUBLIC и классом поиска в M1 может получить доступ к общедоступным типам в M2, когда M2 доступен для M1 и когда тип находится в пакете M2 и экспортируется как минимум в M1.

Lookup на C также может переместиться к целевому классу с помощью методов Lookup.in и MethodHandles.privateLookupIn. Перемещение через модули всегда записывает исходный класс поиска как предыдущий класс поиска и отключает доступ MODULE. Если целевой класс находится в том же модуле, что и класс поиска C, тогда целевой класс становится новым классом поиска и предыдущий класс поиска не меняется. Если целевой класс находится в другом модуле, отличном от модуля класса поиска M1 (модуля C), C становится новым предыдущим классом поиска, а целевой класс — новым классом поиска. В этом случае, если уже существует предыдущий класс поиска в M0, и он отличается от M1 и M2, тогда полученный поиск теряет все привилегии. Например,

 
 Lookup lookup = MethodHandles.lookup();   // in class C
 Lookup lookup2 = lookup.in(D.class);
 MethodHandle mh = lookup2.findStatic(E.class, "m", MT);
 

Фабричный метод MethodHandles.lookup() создает объект Lookup с null предыдущим классом поиска. lookup.in(D.class) преобразует lookup в классе C в класс D без повышения привилегий. Если C и D находятся в одном модуле, lookup2 записывает D в качестве нового класса поиска и сохраняет тот же предыдущий класс поиска, что и исходный lookup, или null, если он не присутствует.

При перемещении Lookup из одного вложения в другое, доступ PRIVATE отключается. При перемещении Lookup из одного пакета в другой, отключается доступ PACKAGE. При перемещении Lookup из одного модуля в другой, отключается доступ MODULE. Перемещение через модули отключает возможность доступа к неэкспортированным классам как в модуле нового класса поиска, так и в модуле старого класса поиска, и результирующий Lookup остается только с доступом PUBLIC. Lookup может перемещаться туда и обратно в класс в модуле класса поиска и модуле предыдущего класса поиска. Перемещение через модули может только уменьшить доступ, но не увеличить его. Перемещение в некоторый третий модуль отключает все виды доступа.

В приведенном выше примере, если C и D находятся в разных модулях, lookup2 записывает D как класс поиска и C как предыдущий класс поиска, и lookup2 имеет только доступ PUBLIC. lookup2 может перемещаться к другим классам в модуле C и модуле D. Если класс E находится в третьем модуле, lookup2.in(E.class) создает Lookup для E без доступа, и класс поиска lookup2 D записывается в качестве предыдущего класса поиска.

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

MethodHandles.privateLookupIn(T.class, lookup) можно использовать для перемещения lookup из класса C в класс T и создания нового Lookup с приватным доступом, если класс поиска разрешено выполнять глубокий рефлексию над T. lookup должен иметь MODULE и PRIVATE доступ для вызова privateLookupIn. Модуль lookup в модуле M1 разрешено выполнять глубокий рефлексию над всеми классами в M1. Если T находится в M1, privateLookupIn создает новый Lookup по T с полными возможностями. Модуль lookup в C также разрешено выполнять глубокий рефлексию над T в другом модуле M2, если M1 читает M2 и M2 opens пакет, содержащий T, по крайней мере, до M1. T становится новым классом поиска, а C — новым предыдущим классом поиска, и доступ MODULE удаляется из полученного Lookup. Полученный Lookup можно использовать для поиска членов или перехода к другому классу поиска, вызвав Lookup::in. Но его нельзя использовать для получения другого приватного Lookup вызвав privateLookupIn, так как у него нет MODULE доступа.

Проверка доступа между модулями

Lookup с PUBLIC или UNCONDITIONAL режимом разрешает межмодульный доступ. Проверка доступа выполняется относительно класса поиска и предыдущего класса поиска, если он есть.

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

Если Lookup по LC в M1 не имеет предыдущего класса поиска, поиск с PUBLIC режимом может получить доступ ко всем публичным типам в модулях, которые читаемы для M1, и тип находится в пакете, экспортированном по крайней мере для M1.

Если Lookup по LC в M1 имеет предыдущий класс поиска PLC по M0, поиск с PUBLIC режимом может получить доступ к пересечению всех публичных типов, доступных для M1 и всех публичных типов, доступных для M0. M0 читает M1, и поэтому множество доступных типов включает:

Публичные типы в следующих пакетах доступны для класса поиска и предыдущего класса поиска.
Типы, равнодоступные для M0 и M1
Безусловно экспортированные пакеты из M1
Безусловно экспортированные пакеты из M0 если M1 читает M0
Безусловно экспортированные пакеты из третьего модуля M2 если оба M0 и M1 читают M2
Квалифицированные экспортированные пакеты из M1 в M0
Квалифицированные экспортированные пакеты из M0 в M1 если M1 читает M0
Квалифицированные экспортированные пакеты из третьего модуля M2 в оба M0 и M1 если оба M0 и M1 читают M2

Режимы доступа

В таблице ниже показаны режимы доступа Lookup , полученного любым из следующих методов фабрики или преобразования:
  • MethodHandles::lookup
  • MethodHandles::publicLookup
  • MethodHandles::privateLookupIn
  • Lookup::in
  • Lookup::dropLookupMode
Сводка режимов доступа
Объект поиска Оригинальный Защищенный Приватный Пакет Модуль Публичный
CL = MethodHandles.lookup() в C ORI PRO PRI PAC MOD 1R
CL.in(C1) в том же пакете PAC MOD 1R
CL.in(C1) в том же модуле MOD 1R
CL.in(D) в другом модуле 2R
CL.in(D).in(C) вернуться в модуль 2R
PRI1 = privateLookupIn(C1,CL) PRO PRI PAC MOD 1R
PRI1a = privateLookupIn(C,PRI1) PRO PRI PAC MOD 1R
PRI1.in(C1) в том же пакете PAC MOD 1R
PRI1.in(C1) в другом пакете MOD 1R
PRI1.in(D) в другом модуле 2R
PRI1.dropLookupMode(PROTECTED) PRI PAC MOD 1R
PRI1.dropLookupMode(PRIVATE) PAC MOD 1R
PRI1.dropLookupMode(PACKAGE) MOD 1R
PRI1.dropLookupMode(MODULE) 1R
PRI1.dropLookupMode(PUBLIC) нет
PRI2 = privateLookupIn(D,CL) PRO PRI PAC 2R
privateLookupIn(D,PRI1) PRO PRI PAC 2R
privateLookupIn(C,PRI2) не удалось IAE
PRI2.in(D2) в том же пакете PAC 2R
PRI2.in(D2) в другом пакете 2R
PRI2.in(C1) вернуться в модуль 2R
PRI2.in(E) перейти в третий модуль нет
PRI2.dropLookupMode(PROTECTED) PRI PAC 2R
PRI2.dropLookupMode(PRIVATE) PAC 2R
PRI2.dropLookupMode(PACKAGE) 2R
PRI2.dropLookupMode(MODULE) 2R
PRI2.dropLookupMode(PUBLIC) нет
CL.dropLookupMode(PROTECTED) PRI PAC MOD 1R
CL.dropLookupMode(PRIVATE) PAC MOD 1R
CL.dropLookupMode(PACKAGE) MOD 1R
CL.dropLookupMode(MODULE) 1R
CL.dropLookupMode(PUBLIC) нет
PUB = publicLookup() У
PUB.in(D) в другом модуле У
PUB.in(D).in(E) третий модуль У
PUB.dropLookupMode(UNCONDITIONAL) нет
privateLookupIn(C1,PUB) не удалось IAE
ANY.in(X), для недоступного X нет

Примечания:

  • Классы C и C1 находятся в модуле M1, но D и D2 находятся в модуле M2, а E находится в модуле M3. X обозначает класс, который недоступен для поиска. ANY обозначает любой из примеров поиска.
  • ORI указывает на установленный бит ORIGINAL, PRO указывает на установленный бит PROTECTED, PRI указывает на установленный бит PRIVATE, PAC указывает на установленный бит PACKAGE, MOD указывает на установленный бит MODULE, 1R и 2R указывают на установленный бит PUBLIC, U указывает на установленный бит UNCONDITIONAL, IAE указывает на исключение IllegalAccessException.
  • Доступ к публичным членам бывает трех типов:
    • безусловный (U): поиск предполагает возможность чтения. У запроса есть null предыдущий класс поиска.
    • чтение в одном модуле (1R): проверка доступа модуля выполняется относительно класса поиска. У запроса есть null предыдущий класс поиска.
    • чтение в двух модулях (2R): проверка доступа модуля выполняется относительно класса поиска и предыдущего класса поиска. У запроса есть непустой предыдущий класс поиска, находящийся в другом модуле по сравнению с текущим классом поиска.
  • Любая попытка обратиться к третьему модулю теряет весь доступ.
  • Если целевой класс X недоступен для Lookup::in, все режимы доступа отменяются.

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

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

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

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

Если менеджер безопасности присутствует и текущий объект поиска не имеет полных привилегий доступа, то вызовы defineClass, defineHiddenClass, defineHiddenClassWithClassData вызывают smgr.checkPermission с RuntimePermission("defineClass").

Методы, чувствительные к вызывающему объекту

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

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

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

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

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

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

Краткое описание вложенных классов

Модификатор и тип Класс Описание
static enum  MethodHandles.Lookup.ClassOption
Набор параметров класса, которые указывают, добавляется ли динамически созданный с помощью метода Lookup::defineHiddenClass скрытый класс как новый член вложенного класса и/или имеет ли скрытый класс тесную связь с загрузчиком классов, отмеченным как его определяющий загрузчик.

Краткое описание полей

Модификатор и тип Поле Описание
static final int MODULE
Однобитовая маска, представляющая доступ module, который может влиять на результат lookupModes.
static final int ORIGINAL
Однобитовая маска, представляющая доступ original, который может влиять на результат lookupModes.
static final int PACKAGE
Однобитовая маска, представляющая доступ package (доступ по умолчанию), который может влиять на результат lookupModes.
static final int PRIVATE
Однобитовая маска, представляющая доступ private, который может влиять на результат lookupModes.
static final int PROTECTED
Однобитовая маска, представляющая доступ protected, который может влиять на результат lookupModes.
static final int PUBLIC
Однобитовая маска, представляющая доступ public, который может влиять на результат lookupModes.
static final int UNCONDITIONAL
Однобитовая маска, представляющая доступ unconditional, который может влиять на результат lookupModes.

Краткое описание методов

Модификатор и тип Метод Описание
Class<?> accessClass(Class<?> targetClass)
Определяет, можно ли получить доступ к классу из контекста поиска, определенного этим объектом Lookup.
MethodHandle bind(Object receiver, String name, MethodType type)
Создает обработчик метода со связыванием на этапе компиляции для нестатического метода.
Class<?> defineClass(byte[] bytes)
Создает и связывает класс или интерфейс из bytes с тем же загрузчиком классов и в том же пакете времени выполнения и областью защиты, что и класс поиска этого поиска класс поиска, как при вызове ClassLoader::defineClass.
MethodHandles.Lookup defineHiddenClass(byte[] bytes, boolean initialize, MethodHandles.Lookup.ClassOption... options)
Создает скрытый класс или интерфейс из bytes, возвращая Lookup для вновь созданного класса или интерфейса.
MethodHandles.Lookup defineHiddenClassWithClassData(byte[] bytes, Object classData, boolean initialize, MethodHandles.Lookup.ClassOption... options)
Создает скрытый класс или интерфейс из bytes с присоединенными данными класса, возвращая Lookup для вновь созданного класса или интерфейса.
MethodHandles.Lookup dropLookupMode(int modeToDrop)
Создает поиск в том же классе поиска, в котором этот объект поиска находит члены, но с режимом поиска, который потерял данный режим поиска.
Class<?> ensureInitialized(Class<?> targetClass)
Обеспечивает инициализацию targetClass.
Class<?> findClass(String targetName)
Ищет класс по имени из контекста поиска, определенного этим объектом Lookup, как если бы он был разрешен инструкцией ldc.
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)
Создает обработчик метода, предоставляющий доступ для записи в статическое поле.
VarHandle findStaticVarHandle(Class<?> decl, String name, Class<?> type)
Создает VarHandle, предоставляющий доступ к статическому полю name типа type, объявленному в классе типа decl.
VarHandle findVarHandle(Class<?> recv, String name, Class<?> type)
Создает VarHandle, предоставляющий доступ к нестатическому полю name типа type, объявленному в классе типа recv.
MethodHandle findVirtual(Class<?> refc, String name, MethodType type)
Создает обработчик метода для виртуального метода.
boolean hasFullPrivilegeAccess()
Возвращает true, если этот поиск имеет полный доступ к привилегиям, т.е.
boolean hasPrivateAccess()
Устарело.
Этот метод изначально предназначался для проверки доступа PRIVATE, который подразумевает полный доступ к привилегиям, но доступ MODULE с тех пор стал независимым от доступа PRIVATE.
MethodHandles.Lookup in(Class<?> requestedLookupClass)
Создает поиск в указанном новом классе поиска.
Class<?> lookupClass()
Указывает, какой класс выполняет поиск.
int lookupModes()
Указывает, к классам защиты доступа каких членов может получить доступ этот объект поиска.
Class<?> previousLookupClass()
Сообщает о классе поиска в другом модуле, из которого этот объект поиска был ранее перемещен, или null.
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)
Создает обработчик метода для отраженного метода.
VarHandle unreflectVarHandle(Field f)
Создает VarHandle, предоставляющий доступ к отраженному полю f типа T, объявленному в классе типа R.

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

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

Подробное описание полей

PUBLIC

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

Объект с этим режимом поиска выполняет проверку доступа между модулями относительно класса поиска lookup class и предыдущего класса поиска previous lookup class, если он присутствует.

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

PRIVATE

public static final int PRIVATE
Маска из одного бита, представляющая доступ private, который может повлиять на результат lookupModes. Значение, 0x02, совпадает со значением бита модификатора private modifier bit.
См. также:
  • Значения константных полей

PROTECTED

public static final int PROTECTED
Маска из одного бита, представляющая доступ protected, который может повлиять на результат lookupModes. Значение, 0x04, совпадает со значением бита модификатора protected modifier bit.
См. также:
  • Значения константных полей

PACKAGE

public static final int PACKAGE
Маска из одного бита, представляющая доступ package (доступ по умолчанию), который может повлиять на результат lookupModes. Значение равно 0x08, которое не соответствует ни одному конкретному биту модификатора.
См. также:
  • Значения константных полей

MODULE

public static final int MODULE
Маска из одного бита, представляющая доступ module, который может повлиять на результат lookupModes. Значение равно 0x10, которое не соответствует ни одному конкретному биту модификатора. В сочетании с битом модификатора PUBLIC, объект с этим режимом поиска может получить доступ ко всем публичным типам в модуле класса поиска и публичным типам в пакетах, экспортированных другими модулями в модуль класса поиска.

Если этот режим поиска установлен, предыдущий класс поиска previous lookup class всегда null.

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

БЕЗУСЛОВНЫЙ

public static final int UNCONDITIONAL
Маска из одного бита, представляющая доступ unconditional, который может повлиять на результат lookupModes. Значение равно 0x20, которое не соответствует ни одному конкретному биту модификатора. Объект с этим режимом поиска предполагает чтение. Этот режим поиска может получить доступ ко всем публичным членам публичных типов всех модулей, когда тип находится в пакете, который exported unconditionally.

Если этот режим поиска установлен, предыдущий класс поиска previous lookup class всегда null.

С:
9
См. также:
  • MethodHandles.publicLookup()
  • Значения константных полей

ИСТОЧНИК

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

Если этот режим поиска установлен, объект Lookup должен быть создан исходным классом поиска, вызвав метод MethodHandles.lookup() или методом инициализации, вызванным виртуальной машиной. Объект Lookup с этим режимом поиска имеет полный привилегированный доступ.

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

Подробное описание методов

lookupClass

public Class<?> lookupClass()
Указывает, какой класс выполняет поиск. Именно против этого класса выполняются проверки видимости и разрешений на доступ.

Если у этого объекта поиска есть предыдущий класс поиска, проверки доступа выполняются как для класса поиска, так и для предыдущего класса поиска.

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

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

previousLookupClass

public Class<?> previousLookupClass()
Сообщает о классе поиска в другом модуле, из которого этот объект поиска был ранее перемещен, или null.

Объект Lookup, созданный методами-фабриками, такими как метод lookup() и publicLookup(), имеет null предыдущий класс поиска. Объект Lookup имеет непустой предыдущий класс поиска, когда этот поиск был перенесен из старого класса поиска в одном модуле в новый класс поиска в другом модуле.

Возвращает:
класс поиска в другом модуле, из которого этот объект поиска был ранее перемещен, или null
С:
14
См. также:
  • in(Class)
  • MethodHandles.privateLookupIn(Class, Lookup)
  • Поиск между модулями

режимыПоиска

public int lookupModes()
Указывает, какие классы защиты доступа к членам может создать этот объект поиска. Результат — битовая маска битов PUBLIC (0x01), PRIVATE (0x02), PROTECTED (0x04), PACKAGE (0x08), MODULE (0x10), БЕЗУСЛОВНЫЙ (0x20) и ИСТОЧНИК (0x40).

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

Возвращает:
режимы поиска, которые ограничивают типы доступа, выполняемые этим объектом поиска
См. также:
  • in(java.lang.Class<?>)
  • dropLookupMode(int)

in

public MethodHandles.Lookup in(Class<?> requestedLookupClass)
Создаёт поиск по указанному новому классу поиска. Результирующий объект будет сообщать о указанном классе как о своём собственном lookupClass.

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

  • Если новый класс поиска отличается от старого класса поиска, т.е. доступ ORIGINAL теряется.
  • Если новый класс поиска находится в другом модуле, чем старый, т.е. доступ MODULE теряется.
  • Если новый класс поиска находится в другом пакете, чем старый, защищённые и по умолчанию (пакета) члены не будут доступны, т.е. доступ PROTECTED и PACKAGE теряются.
  • Если новый класс поиска не находится в том же члене пакета, что и старый, частные члены не будут доступны, и защищённые члены не будут доступны благодаря наследованию, т.е. доступ PRIVATE теряется. (Защищённые члены могут оставаться доступными из-за совместного использования пакетов.)
  • Если новый класс поиска не доступен для этого поиска, то ни один член, даже публичный, не будет доступен, т.е. все режимы доступа теряются.
  • Если новый класс поиска, старый класс поиска и предыдущий класс поиска находятся в разных модулях, т.е. перемещение в третий модуль, все режимы доступа теряются.

Новый предыдущий класс поиска выбирается следующим образом:

  • Если у нового объекта поиска установлен бит UNCONDITIONAL, новый предыдущий класс поиска — null.
  • Если новый класс поиска находится в том же модуле, что и старый класс поиска, новый предыдущий класс поиска — старый предыдущий класс поиска.
  • Если новый класс поиска находится в другом модуле, чем старый класс поиска, новый предыдущий класс поиска — старый класс поиска.

Возможности результирующего поиска по загрузке классов (используемые во время вызовов findClass(java.lang.String)) определяются загрузчиком класса поиска, который может измениться в результате этой операции.

Parameters:
requestedLookupClass - желаемый класс поиска для нового объекта поиска
Returns:
объект поиска, который сообщает о желаемом классе поиска, или тот же объект, если изменений нет
Throws:
IllegalArgumentException - если requestedLookupClass является примитивным типом или пустым или массивом классов
NullPointerException - если аргумент равен null
See Also:
  • accessClass(Class)
  • Перекрёстные поиски модулей

dropLookupMode

public MethodHandles.Lookup dropLookupMode(int modeToDrop)
Создаёт поиск по тому же классу поиска, который этот объект поиска находит члены, но с режимом поиска, в котором потерян указанный режим поиска. Режим поиска для удаления — один из PUBLIC, MODULE, PACKAGE, PROTECTED, PRIVATE, ORIGINAL или UNCONDITIONAL.

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

Если этот поиск не является публичным, то следующее применимо независимо от его режимов поиска. PROTECTED и ORIGINAL всегда удаляются, поэтому результирующий режим поиска никогда не будет иметь этих прав доступа. При удалении PACKAGE результирующий поиск не будет иметь PACKAGE или PRIVATE доступа. При удалении MODULE результирующий поиск не будет иметь MODULE, PACKAGE, или PRIVATE доступа. При удалении PUBLIC результирующий поиск не имеет доступа.

API Note:
Поиск с режимом PACKAGE но без режима PRIVATE может безопасно делегировать доступ не к публичным членам внутри пакета класса поиска без предоставления частного доступа. Поиск с режимом MODULE но без режима PACKAGE может безопасно делегировать PUBLIC доступ внутри модуля класса поиска без предоставления доступа к пакету. Поиск с предыдущим классом поиска (и режимом PUBLIC но без режима MODULE ) может безопасно делегировать доступ к публичным классам, доступным как для модуля класса поиска, так и для модуля предыдущего класса поиска.
Parameters:
modeToDrop - режим поиска для удаления
Returns:
объект поиска, в котором отсутствует указанный режим, или тот же объект, если изменений нет
Throws:
IllegalArgumentException - если modeToDrop не является одним из PUBLIC, MODULE, PACKAGE, PROTECTED, PRIVATE, ORIGINAL или UNCONDITIONAL
Since:
9
See Also:
  • MethodHandles.privateLookupIn(java.lang.Class<?>, java.lang.invoke.MethodHandles.Lookup)

defineClass

public Class<?> defineClass(byte[] bytes) throws IllegalAccessException
Создаёт и связывает класс или интерфейс из bytes с тем же загрузчиком классов и в том же пакете среды выполнения и домене защиты, что и класс поиска этого поиска, как если бы вызывали ClassLoader::defineClass.

Режимы поиска для этого поиска должны включать доступ PACKAGE, так как члены пакета по умолчанию (пакета) будут доступны для класса. Режим поиска PACKAGE служит для проверки того, что объект поиска был создан вызывающим элементом в пакете среды выполнения (или получен из поиска, первоначально созданного кодом с надлежащими привилегиями, для целевого класса в пакете среды выполнения).

Параметр bytes — это байты класса допустимого файла класса (как определено в Спецификации виртуальной машины Java) с именем класса в том же пакете, что и класс поиска.

Этот метод не выполняет инициализатор класса. Инициализатор класса может быть выполнен в более позднее время, как подробно описано в разделе 12.4 Спецификации языка Java.

Если присутствует менеджер безопасности и у этого поиска нет полного привилегированного доступа, сначала вызывается его метод checkPermission для проверки RuntimePermission("defineClass").

Parameters:
bytes - байты класса
Returns:
объект Class для класса
Throws:
IllegalAccessException - если у этого поиска нет доступа PACKAGE
ClassFormatError - если bytes не является структурой ClassFile
IllegalArgumentException - если bytes обозначает класс в другом пакете, чем класс поиска, или bytes не является классом или интерфейсом (флаг ACC_MODULE установлен в значении элемента access_flags)
VerifyError - если вновь созданный класс не может быть проверен
LinkageError - если вновь созданный класс не может быть связан по какой-либо другой причине
SecurityException - если менеджер безопасности присутствует и он отказывает в доступе
NullPointerException - если bytes — null
Since:
9
See Also:
  • MethodHandles.privateLookupIn(java.lang.Class<?>, java.lang.invoke.MethodHandles.Lookup)
  • dropLookupMode(int)
  • ClassLoader.defineClass(String,byte[],int,int,ProtectionDomain)

defineHiddenClass

public MethodHandles.Lookup defineHiddenClass(byte[] bytes, boolean initialize, MethodHandles.Lookup.ClassOption... options) throws IllegalAccessException
Создаёт скрытый класс или интерфейс из bytes, возвращая Lookup для вновь созданного класса или интерфейса.

Обычно класс или интерфейс C создаётся загрузчиком классов, который либо определяет C напрямую, либо делегирует задачу другому загрузчику классов. Загрузчик классов определяет C напрямую, вызывая ClassLoader::defineClass, что заставляет виртуальную машину Java вывести C из предполагаемого представления в формате class файла. В ситуациях, когда использование загрузчика классов нежелательно, класс или интерфейс C может быть создан этим методом вместо этого. Этот метод способен определить C, а тем самым создать его, не вызывая ClassLoader::defineClass. Вместо этого этот метод определяет C так, как будто виртуальная машина Java выводит не-массивный класс или интерфейс C из предполагаемого представления в формате class файла, используя следующие правила:

  1. Режим поиска (режимы поиска) для данного Lookup должны включать полномочия полного доступа. Этот уровень доступа необходим для создания C в модуле класса поиска данного Lookup.
  2. Предполагаемое представление в bytes должно быть структурой ClassFile (JVMS 4.1) с поддерживаемой основной и дополнительной версиями. Основная и дополнительная версии могут отличаться от версии файла class класса поиска данного Lookup.
  3. Значение this_class должно быть допустимым индексом в таблице constant_pool, а запись в этой позиции — допустимой структурой CONSTANT_Class_info. Пусть N — бинарное имя, закодированное во внутреннем формате, указанное в этой структуре. N должно обозначать класс или интерфейс в том же пакете, что и класс поиска.
  4. Пусть CN — строка N + "." + <suffix>, где <suffix> — неопределённое имя.

    Пусть newBytes — структура ClassFile, заданная bytes, с дополнительной записью в таблице constant_pool, указывающей на структуру CONSTANT_Utf8_info для CN, и где структура CONSTANT_Class_info, указанная this_class, относится к новой структуре CONSTANT_Utf8_info.

    Пусть L — определяющий загрузчик классов класса поиска данного Lookup.

    C выводится с именем CN, загрузчиком классов L, и предполагаемым представлением newBytes как если бы это происходило согласно правилам JVMS 5.3.5, с следующими корректировками:

    • Постоянная, указанная this_class, может указывать имя, содержащее единственный символ ".", даже если это не является допустимым бинарным именем класса или интерфейса во внутреннем формате.
    • Виртуальная машина Java отмечает L в качестве определяющего загрузчика классов C, но загрузчик классов не регистрируется как инициализирующий загрузчик классов C.
    • C считается имеющим тот же выполняемый пакет, модуль и домен защиты, что и класс поиска данного Lookup.
    • Пусть GN — бинарное имя, полученное путём взятия N (бинарного имени, закодированного во внутреннем формате) и замены косой черты ASCII точкой ASCII. В случае Class, представляющего C,
      • Class.getName() возвращает строку GN + "/" + <suffix>, даже если это не является допустимым бинарным именем класса или интерфейса.
      • Class.descriptorString() возвращает строку "L" + N + "." + <suffix> + ";", даже если это не является допустимым именем описателя типа.
      • Class.describeConstable() возвращает пустой необязательный параметр, так как C не может быть описан в номинальной форме.

После того, как C будет выведен, он будет связан виртуальной машиной Java. Связывание происходит так, как указано в JVMS 5.4.3, с следующими корректировками:

  • Во время проверки, когда необходимо загрузить класс с именем CN, попытка завершается успешно, создавая класс C. Никакие запросы к загрузчику классов не производятся.
  • При любой попытке разрешить запись в пуле постоянных времени выполнения, указанную this_class, символическая ссылка считается разрешенной до C, и разрешение всегда происходит мгновенно.

Если параметр initialize равен true, то C инициализируется виртуальной машиной Java.

Созданный класс или интерфейс C служит классом поиска Lookup объекта, возвращённого этим методом. C является скрытым в том смысле, что никакой другой класс или интерфейс не может обратиться к C через запись в пуле постоянных. То есть, скрытый класс или интерфейс не может быть назван в качестве супертипа, типа поля, типа параметра метода или типа возвращаемого значения любым другим классом. Это связано с тем, что скрытый класс или интерфейс не имеет бинарного имени, поэтому нет внутреннего представления, которое можно записать в пуле постоянных какого-либо класса. Скрытый класс или интерфейс недоступен для Class.forName(String, boolean, ClassLoader), ClassLoader.loadClass(String, boolean) или findClass(String) и не может быть изменён агентами Java или инструментальными агентами, использующими JVM Tool Interface.

Класс или интерфейс, созданный загрузчиком классов, имеет тесную связь с этим загрузчиком. То есть, каждый объект Class содержит ссылку на загрузчик ClassLoader, который его определил. Это означает, что класс, созданный загрузчиком классов, может быть разгружен только в том случае, если его определяющий загрузчик недоступен и, следовательно, может быть удалён сборщиком мусора (JLS 12.7). Однако по умолчанию скрытый класс или интерфейс может быть разгружен, даже если загрузчик классов, отмеченный в качестве его определяющего загрузчика, доступен. Это поведение полезно, когда скрытый класс или интерфейс обслуживает несколько классов, определённых произвольными загрузчиками классов. В других случаях скрытый класс или интерфейс может быть связан с одним классом (или небольшим количеством классов) с тем же определяющим загрузчиком, что и скрытый класс или интерфейс. В таких случаях, когда скрытый класс или интерфейс должен совпадать по времени с обычным классом или интерфейсом, опция STRONG может быть передана в options. Это обеспечивает, чтобы скрытый класс имел ту же тесную связь с загрузчиком классов, отмеченным как его определяющий загрузчик, что и обычный класс или интерфейс со своим определяющим загрузчиком. Если STRONG не используется, то вызывающий defineHiddenClass по-прежнему может предотвратить разгрузку скрытого класса или интерфейса, гарантируя, что объект Class доступен.

Характеристики разгрузки устанавливаются для каждого скрытого класса при его определении и не могут быть изменены позже. Преимущество разрешения разгрузки скрытых классов независимо от загрузчика классов, отмеченного как их определяющий загрузчик, заключается в том, что приложение может создать очень большое количество скрытых классов. В противном случае, если STRONG используется, у JVM может закончиться память, как если бы обычные классы были созданы загрузчиками классов.

Классы и интерфейсы в одном наборе допускают взаимный доступ к своим закрытым членам. Связь наборов определяется атрибутом NestHost (JVMS 4.7.28) и атрибутом NestMembers (JVMS 4.7.29) в файле class. По умолчанию скрытый класс принадлежит набору, состоящему только из него самого, потому что скрытый класс не имеет бинарного имени. Опция NESTMATE может быть передана в options для создания скрытого класса или интерфейса C как члена набора. Набор, которому принадлежит C, не основан на атрибуте NestHost в структуре ClassFile файла, из которого C был выведен. Вместо этого следующие правила определяют хост набора C:

  • Если хост набора класса поиска данного Lookup был ранее определён, то пусть H будет хостом набора класса поиска. В противном случае хост набора класса поиска определяется по алгоритму JVMS 5.4.4, что даёт H.
  • Хост набора C определяется как H, хост набора класса поиска.

Скрытый класс или интерфейс может быть сериализуемым, но это требует специального механизма сериализации, чтобы гарантировать правильную сериализацию и десериализацию экземпляров. Механизм сериализации по умолчанию поддерживает только классы и интерфейсы, которые могут быть найдены по их имени класса.

Параметры:
bytes - байты, составляющие данные класса, в формате допустимого class файла, как определено в Спецификации виртуальной машины Java.
initialize - если true класс будет инициализирован.
options - параметры класса
Возвращает:
объект Lookup скрытого класса с исходным и полным доступом
Исключение:
IllegalAccessException - если у этого Lookup нет полного доступа
SecurityException - если менеджер безопасности присутствует и он отказывает в доступе
ClassFormatError - если bytes не является структурой ClassFile
UnsupportedClassVersionError - если bytes не соответствует поддержанной мажорной или минорной версии
IllegalArgumentException - если bytes обозначает класс в другом пакете, чем класс поиска, или bytes не является классом или интерфейсом (флаг ACC_MODULE установлен в значении элемента access_flags)
IncompatibleClassChangeError - если класс или интерфейс, указанный как непосредственный суперкласс C, на самом деле является интерфейсом, или если любой из классов или интерфейсов, указанных как непосредственные суперинтерфейсы C, на самом деле не является интерфейсом
ClassCircularityError - если любой из суперклассов или суперинтерфейсов C является C самим собой
VerifyError - если созданный класс не может быть проверен
LinkageError - если созданный класс не может быть связан по другим причинам
NullPointerException - если любой параметр null
См. Спецификацию языка Java:
12.7 Выгрузка классов и интерфейсов
См. Спецификацию виртуальной машины Java:
4.2.1 Имена бинарных классов и интерфейсов
4.2.2 Неопределенные имена
4.7.28 Атрибут NestHost
4.7.29 Атрибут NestMembers
5.4.3.1 Разрешение классов и интерфейсов
5.4.4 Контроль доступа
5.3.5 Получение Class из представления файла class
5.4 Связывание
5.5 Инициализация
С:
15
См. также:
  • Class.isHidden()

defineHiddenClassWithClassData

public MethodHandles.Lookup defineHiddenClassWithClassData(byte[] bytes, Object classData, boolean initialize, MethodHandles.Lookup.ClassOption... options) throws IllegalAccessException
Создаёт скрытый класс или интерфейс из bytes с ассоциированными данными класса, возвращая Lookup для нового класса или интерфейса.

Этот метод эквивалентен вызову defineHiddenClass(bytes, initialize, options) как если бы скрытый класс был введён с приватным статическим конечным неопределённым полем, инициализированным заданными classData в первой инструкции инициализатора класса. Созданный класс связывается виртуальной машиной Java.

Методы MethodHandles::classData и MethodHandles::classDataAt могут быть использованы для получения classData.

Примечание API:
Фреймворк может создать скрытый класс с данными класса с одним или несколькими объектами и загрузить данные класса как динамически вычисленные константы через метод запуска. Class data доступен только объекту поиска, созданному новым скрытым классом, но недоступен другим членам в том же вложении (в отличие от приватных статических полей, доступных сотоварищам по вложению). Следует проявлять осторожность в отношении изменяемости, например, при передаче массива или другой изменяемой структуры через данные класса. Изменение любых значений, хранящихся в данных класса во время выполнения, может привести к непредсказуемому поведению. Если данные класса являются List, рекомендуется сделать их неизменяемыми, например, через List::of.
Параметры:
bytes - байты класса
classData - предварительно инициализированные данные класса
initialize - если true класс будет инициализирован.
options - параметры класса
Возвращает:
объект Lookup скрытого класса с исходным и полным доступом
Исключение:
IllegalAccessException - если у этого Lookup нет полного доступа
SecurityException - если менеджер безопасности присутствует и он отказывает в доступе
ClassFormatError - если bytes не является структурой ClassFile
UnsupportedClassVersionError - если bytes не соответствует поддержанной мажорной или минорной версии
IllegalArgumentException - если bytes обозначает класс в другом пакете, чем класс поиска, или bytes не является классом или интерфейсом (флаг ACC_MODULE установлен в значении элемента access_flags)
IncompatibleClassChangeError - если класс или интерфейс, указанный как непосредственный суперкласс C, на самом деле является интерфейсом, или если любой из классов или интерфейсов, указанных как непосредственные суперинтерфейсы C, на самом деле не является интерфейсом
ClassCircularityError - если любой из суперклассов или суперинтерфейсов C является C самим собой
VerifyError - если созданный класс не может быть проверен
LinkageError - если созданный класс не может быть связан по другим причинам
NullPointerException - если любой параметр null
См. Спецификацию языка Java:
12.7 Выгрузка классов и интерфейсов
См. Спецификацию виртуальной машины Java:
4.2.1 Имена бинарных классов и интерфейсов
4.2.2 Неопределенные имена
4.7.28 Атрибут NestHost
4.7.29 Атрибут NestMembers
5.4.3.1 Разрешение классов и интерфейсов
5.4.4 Контроль доступа
5.3.5 Получение Class из представления файла class
5.4 Связывание
5.5 Инициализация
С:
16
См. также:
  • defineHiddenClass(byte[], boolean, ClassOption...)
  • Class.isHidden()
  • MethodHandles.classData(Lookup, String, Class)
  • MethodHandles.classDataAt(Lookup, String, Class, int)

toString

public String toString()
Отображает имя класса, для которого выполняются запросы, за которым следует «/» и имя предыдущего класса поиска, если оно есть. (Имя — это то, что возвращает Class.getName.) Если на доступ к этому поиску есть ограничения, это обозначается добавлением суффикса к имени класса, состоящего из косой черты и ключевого слова. Ключевое слово представляет собой наиболее строгий разрешенный доступ и выбирается следующим образом:
  • Если доступ запрещен, суффикс — «/noaccess».
  • Если разрешен только безусловный доступ, суффикс — «/publicLookup».
  • Если разрешен только публичный доступ к типам в экспортированных пакетах, суффикс — «/public».
  • Если разрешен только публичный и модульный доступ, суффикс — «/module».
  • Если разрешен публичный и пакетный доступ, суффикс — «/package».
  • Если разрешены публичный, пакетный и частный доступ, суффикс — «/private».
Если ни один из вышеперечисленных случаев не применим, то разрешен полный привилегированный доступ (публичный, модульный, пакетный, частный и защищенный). В этом случае суффикс не добавляется. Это верно только для объекта, изначально полученного из MethodHandles.lookup. Объекты, созданные Lookup.in, всегда имеют ограниченный доступ и отображают суффикс.

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

Overrides:
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) в начале. Метод и все его типы аргументов должны быть доступны объекту поиска.

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

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

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

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

Если класс VarHandle и строка имени соответствует имени метода с сигнатурно-полиморфным режимом доступа, результирующий обработчик метода эквивалентен обработчику, произведённому MethodHandles.varHandleInvoker(java.lang.invoke.VarHandle.AccessMode, java.lang.invoke.MethodType) с режимом доступа, соответствующим строке имени, и с теми же аргументами 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

findClass

public Class<?> findClass(String targetName) throws ClassNotFoundException, IllegalAccessException
Ищет класс по имени из контекста поиска, определённого этим объектом Lookup, как если бы он был решён инструкцией ldc. Такой поиск, как указано в JVMS 5.4.3.1, пытается найти и загрузить класс, а затем определяет, доступен ли класс для этого объекта поиска.

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

Параметры:
targetName - полное квалифицированное имя искомого класса.
Возвращает:
запрашиваемый класс.
Исключения:
SecurityException - если менеджер безопасности присутствует и им отказано в доступе
LinkageError - если происходит сбой привязке
ClassNotFoundException - если класс не может быть загружен загрузчиком класса поиска.
IllegalAccessException - если класс недоступен, используя разрешенные режимы доступа.
NullPointerException - если targetName равен null
См. Спецификацию виртуальной машины Java:
5.4.3.1 Разрешение классов и интерфейсов
С:
9

ensureInitialized

public Class<?> ensureInitialized(Class<?> targetClass) throws IllegalAccessException
Обеспечивает, что targetClass был инициализирован. Класс, подлежащий инициализации, должен быть доступен для этого объекта Lookup. Этот метод вызывает инициализацию targetClass, если она ещё не была выполнена, как указано в спецификации JVMS 5.5.
Параметры:
targetClass - класс, подлежащий инициализации
Возвращает:
targetClass , который был инициализирован
Изначает исключения:
IllegalArgumentException - если targetClass является примитивным типом или классом void или массива
IllegalAccessException - если targetClass недоступен для этого поиска
ExceptionInInitializerError - если инициализация класса, вызванная этим методом, завершилась неудачей
SecurityException - если менеджер безопасности присутствует и он отказывается предоставить доступ
См. Спецификацию виртуальной машины Java:
5.5 Инициализация
С:
15

accessClass

public Class<?> accessClass(Class<?> targetClass) throws IllegalAccessException
Определяет, может ли к классу быть обеспечен доступ из контекста поиска, определенного этим объектом Lookup. Статический инициализатор класса не выполняется. Если targetClass является классом массива, то targetClass доступен, если тип элемента класса массива доступен. В противном случае, доступность targetClass определяется следующим образом.

Если targetClass находится в том же модуле, что и класс поиска, то класс поиска LC в модуле M1, а предыдущий класс поиска находится в модуле M0 или null, если он отсутствует, то targetClass доступен только в том случае, если выполняется одно из следующих условий:

  • Если у этого поиска есть PRIVATE доступ, то targetClass является LC или другим классом в том же вложенном блоке LC.
  • Если у этого поиска есть PACKAGE доступ, то targetClass находится в той же рабочей папке, что и LC.
  • Если у этого поиска есть MODULE доступ, то targetClass является общедоступным типом в M1.
  • Если у этого поиска есть PUBLIC доступ, то targetClass является общедоступным типом в пакете, экспортированном M1 по крайней мере в M0, если предыдущий класс поиска присутствует; в противном случае targetClass является общедоступным типом в пакете, экспортированном M1 безусловно.

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

В противном случае, targetClass находится в другом модуле, чем lookupClass, и если у этого поиска нет PUBLIC доступа, то lookupClass недоступен.

В противном случае, если у этого поиска нет предыдущего класса поиска, M1 — это модуль, содержащий lookupClass, а M2 — это модуль, содержащий targetClass, то targetClass доступен только в том случае, если

  • M1 считывает M2, и
  • targetClass является общедоступным и находится в пакете, экспортированном M2 по крайней мере в M1.

В противном случае, если у этого поиска есть предыдущий класс поиска, M1 и M2 такие же, как и раньше, а M0 — это модуль, содержащий предыдущий класс поиска, то targetClass доступен только в том случае, если одно из следующих условий истинно:

  • targetClass находится в M0 и M1 считывает M0 и тип находится в пакете, экспортированном в по крайней мере M1.
  • targetClass находится в M1 и M0 считывает M1 и тип находится в пакете, экспортированном по крайней мере в M0.
  • targetClass находится в третьем модуле M2 и M0 и M1 считывают M2 и тип находится в пакете, экспортированном в по крайней мере M0 и M2.

В противном случае, targetClass недоступен.

Параметры:
targetClass - класс, для которого проверяется доступ
Возвращает:
класс, для которого была проверена доступность
Изначает исключения:
IllegalAccessException - если класс недоступен из класса поиска и предыдущего класса поиска, если он присутствует, с использованием разрешенных режимов доступа.
SecurityException - если менеджер безопасности присутствует и он отказывается предоставить доступ
NullPointerException - если targetClass является null
С:
9
См. также:
  • Межмодульные запросы

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 - если проверка доступа завершается неудачей, или если метод является static, или если модификатор переменной арности метода установлен, и 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
См. также:
  • findVarHandle(Class, String, Class)

findSetter

public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
Создает дескриптор метода, обеспечивающий запись в нестатическое поле. Тип дескриптора метода будет иметь тип возвращаемого значения void. Дескриптор метода будет принимать два аргумента: экземпляр, содержащий поле, и значение, которое должно быть сохранено. Второй аргумент будет иметь тип значения поля. Проверка доступа выполняется немедленно от имени класса поиска.
Параметры:
refc - класс или интерфейс, из которого осуществляется доступ к методу
name - имя поля
type - тип поля
Возвращает:
дескриптор метода, который может сохранять значения в поле
Изначает исключения:
NoSuchFieldException - если поле не существует
IllegalAccessException - если проверка доступа завершается неудачей, или если поле является static или final
SecurityException - если менеджер безопасности присутствует и он отказывается предоставить доступ
NullPointerException - если какой-либо аргумент равен null
См. также:
  • findVarHandle(Class, String, Class)

findVarHandle

public VarHandle findVarHandle(Class<?> recv, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
Создаёт VarHandle, предоставляющий доступ к нестатическому полю name типа type, объявленному в классе типа recv. Тип переменной VarHandle — type, а тип координаты — recv.

Проверка доступа выполняется немедленно от имени класса поиска.

Определённые режимы доступа возвращаемого VarHandle недоступны в следующих условиях:

  • если поле объявлено final, режимы записи, атомарного обновления, атомарного обновления числовых значений и атомарного обновления битовых значений недоступны.
  • если тип поля отличается от byte, short, char, int, long, float, или double, то режимы атомарного обновления числовых значений недоступны.
  • если тип поля отличается от boolean, byte, short, char, int, или long, то режимы атомарного обновления битовых значений недоступны.

Если поле объявлено volatile, возвращаемое VarHandle переопределит доступ к полю (в сущности, проигнорирует объявление volatile) в соответствии с его заданными режимами доступа.

Если тип поля — float или double, то режимы числового и атомарного обновления сравнивают значения, используя их битовое представление (см. Float.floatToRawIntBits(float) и Double.doubleToRawLongBits(double) соответственно).

API Note:
Битовое сравнение значений float или значений double, выполняемое режимами числового и атомарного обновления, отличается от оператора == и методов Float.equals(java.lang.Object) и Double.equals(java.lang.Object), в частности в отношении сравнения значений NaN или сравнения -0.0 с +0.0. Следует проявлять осторожность при выполнении операций сравнения и установки или сравнения и обмена с такими значениями, так как операция может неожиданно завершиться неудачей. Существует множество возможных значений NaN, которые считаются NaN в Java, хотя ни одна операция с плавающей запятой IEEE 754, предоставляемая Java, не может отличить их друг от друга. Ошибка выполнения может произойти, если ожидаемое или наблюдаемое значение является значением NaN и оно преобразуется (возможно, специфичным для платформы способом) в другое значение NaN, а значит, имеет другое битовое представление (см. Float.intBitsToFloat(int) или Double.longBitsToDouble(long) для получения более подробной информации). Значения -0.0 и +0.0 имеют разные битовые представления, но считаются равными при использовании оператора ==. Ошибка выполнения может возникнуть, например, если числовой алгоритм вычислит ожидаемое значение, скажем, -0.0, и ранее вычислил наблюдаемое значение, скажем, +0.0.
Parameters:
recv - получающий класс, типа R, объявляющий нестатическое поле
name - имя поля
type - тип поля, типа T
Returns:
VarHandle, предоставляющий доступ к нестатическим полям.
Throws:
NoSuchFieldException - если поле не существует
IllegalAccessException - если проверка доступа завершилась неудачей или если поле static
SecurityException - если менеджер безопасности присутствует и он отклоняет доступ
NullPointerException - если какой-либо аргумент имеет значение null
Since:
9

findStaticGetter

public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
Возвращает обработчик методов, предоставляющий доступ для чтения к статическому полю. Тип обработчика методов будет иметь тип возвращаемого значения поля. Обработчик методов не будет принимать аргументов. Проверка доступа выполняется немедленно от имени класса поиска.

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

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

findStaticSetter

public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
Возвращает обработчик методов, предоставляющий доступ для записи к статическому полю. Тип обработчика методов будет иметь тип возвращаемого значения void. Обработчик методов будет принимать один аргумент типа значения поля, значение, которое должно быть сохранено. Проверка доступа выполняется немедленно от имени класса поиска.

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

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

findStaticVarHandle

public VarHandle findStaticVarHandle(Class<?> decl, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
Возвращает VarHandle, предоставляющий доступ к статическому полю name типа type в классе типа decl. Тип переменной VarHandle — type, и он не имеет типов координат.

Проверка доступа выполняется немедленно от имени класса поиска.

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

Определённые режимы доступа возвращаемого VarHandle недоступны в следующих условиях:

  • если поле объявлено final, режимы записи, атомарного обновления, атомарного обновления числовых значений и атомарного обновления битовых значений недоступны.
  • если тип поля отличается от byte, short, char, int, long, float, или double, то режимы атомарного обновления числовых значений недоступны.
  • если тип поля отличается от boolean, byte, short, char, int, или long, то режимы атомарного обновления битовых значений недоступны.

Если поле объявлено volatile, возвращаемое VarHandle переопределит доступ к полю (в сущности, проигнорирует объявление volatile) в соответствии с его заданными режимами доступа.

Если тип поля — float или double, то режимы числового и атомарного обновления сравнивают значения, используя их битовое представление (см. Float.floatToRawIntBits(float) и Double.doubleToRawLongBits(double) соответственно).

API Note:
Битовое сравнение значений float или значений double, выполняемое режимами числового и атомарного обновления, отличается от оператора == и методов Float.equals(java.lang.Object) и Double.equals(java.lang.Object), в частности в отношении сравнения значений NaN или сравнения -0.0 с +0.0. Следует проявлять осторожность при выполнении операций сравнения и установки или сравнения и обмена с такими значениями, так как операция может неожиданно завершиться неудачей. Существует множество возможных значений NaN, которые считаются NaN в Java, хотя ни одна операция с плавающей запятой IEEE 754, предоставляемая Java, не может отличить их друг от друга. Ошибка выполнения может произойти, если ожидаемое или наблюдаемое значение является значением NaN и оно преобразуется (возможно, специфичным для платформы способом) в другое значение NaN, а значит, имеет другое битовое представление (см. Float.intBitsToFloat(int) или Double.longBitsToDouble(long) для получения более подробной информации). Значения -0.0 и +0.0 имеют разные битовые представления, но считаются равными при использовании оператора ==. Ошибка выполнения может возникнуть, например, если числовой алгоритм вычислит ожидаемое значение, скажем, -0.0, и ранее вычислил наблюдаемое значение, скажем, +0.0.
Parameters:
decl - класс, объявляющий статическое поле
name - имя поля
type - тип поля, типа T
Returns:
VarHandle, предоставляющий доступ к статическому полю
Throws:
NoSuchFieldException - если поле не существует
IllegalAccessException - если проверка доступа завершилась неудачей, или если поле не static
SecurityException - если менеджер безопасности присутствует и он отклоняет доступ
NullPointerException - если какой-либо аргумент имеет значение null
Since:
9

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);
mh1 = mh1.withVarargs(mh0.isVarargsCollector());
return mh1;
 
где defc — это либо receiver.getClass() , либо супертип этого класса, в котором запрашиваемый метод доступен для класса поиска. (В отличие от bind, bindTo не сохраняет переменную арность. Кроме того, bindTo может выбросить ClassCastException в случаях, когда bind выбросил бы IllegalAccessException, как в случае, когда член является protected , а получатель ограничен findVirtual для класса поиска.)
Parameters:
receiver - объект, из которого обращаются к методу
name - имя метода
type - тип метода, без аргумента получателя
Returns:
желаемый обработчик метода
Throws:
NoSuchMethodException - если метод не существует
IllegalAccessException - если проверка доступа не удалась или если бит модификатора переменной арности метода установлен, и asVarargsCollector не удалась
SecurityException - если менеджер безопасности присутствует и он отказывается предоставить доступ
NullPointerException - если какой-либо аргумент равен null
See Also:
  • 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 не общедоступный, не следует передавать полученный обработчик недоверенным сторонам.

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

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

Parameters:
m - отражённый метод
Returns:
обработчик метода, который может вызвать отражённый метод
Throws:
IllegalAccessException - если проверка доступа не удалась или если бит модификатора переменной арности метода установлен, и asVarargsCollector не удалась
NullPointerException - если аргумент равен null

unreflectSpecial

public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException
Создаёт обработчик метода для отражённого метода. Он обойдёт проверки переопределяемых методов на получателе, как если бы он вызывался из инструкции invokespecial внутри явно указанного specialCaller. Тип обработчика метода будет таким же, как у метода, с предложенным типом получателя, соответствующим образом ограниченного. (Тип получателя будет specialCaller или подтип.) Если флаг accessible метода не установлен, проверка доступа выполняется немедленно от имени класса поиска, как если бы инструкция invokespecial связывалась.

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

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

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

unreflectConstructor

public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException
Создаёт обработчик метода для отражённого конструктора. Тип обработчика метода будет таким же, как у конструктора, с изменением типа возврата на класс объявления. Обработчик метода выполнит операцию newInstance, создавая новый экземпляр класса конструктора на аргументах, переданных обработчику метода.

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

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

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

Parameters:
c - отражённый конструктор
Returns:
обработчик метода, который может вызвать отражённый конструктор
Throws:
IllegalAccessException - если проверка доступа не удалась или если бит модификатора переменной арности метода установлен, и asVarargsCollector не удалась
NullPointerException - если аргумент равен null

unreflectGetter

public MethodHandle unreflectGetter(Field f) throws IllegalAccessException
Создаёт обработчик метода, предоставляющий доступ для чтения к отражённому полю. Тип обработчика метода будет иметь тип значения поля в качестве типа возврата. Если поле является static, обработчик метода не будет принимать аргументы. В противном случае его единственный аргумент будет экземпляром, содержащим поле. Если флаг Field объекта accessible не установлен, проверка доступа выполняется немедленно от имени класса поиска.

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

Parameters:
f - отражённое поле
Returns:
обработчик метода, который может загружать значения из отражённого поля
Throws:
IllegalAccessException - если проверка доступа не удалась
NullPointerException - если аргумент равен null

unreflectSetter

public MethodHandle unreflectSetter(Field f) throws IllegalAccessException
Создаёт обработчик метода, предоставляющий доступ для записи в отражённое поле. Тип обработчика метода будет иметь тип void в качестве типа возврата. Если поле является static, обработчик метода будет принимать один аргумент типа значения поля — значение, которое должно быть сохранено. В противном случае два аргумента будут — экземпляр, содержащий поле, и значение, которое должно быть сохранено. Если флаг Field объекта accessible не установлен, проверка доступа выполняется немедленно от имени класса поиска.

Если поле является final, доступ для записи не будет разрешён, и проверка доступа не пройдёт, за исключением некоторых узких обстоятельств, документированных для Field.set. Обработчик метода возвращается только если соответствующий вызов метода Field объекта set мог вернуть нормальное значение. В частности, поля, которые являются одновременно static и final , никогда не могут быть установлены.

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

Parameters:
f - отражённое поле
Returns:
обработчик метода, который может сохранять значения в отражённое поле
Throws:
IllegalAccessException - если проверка доступа не удалась или если поле является final и доступ для записи не разрешён объектом Field
NullPointerException - если аргумент равен null

unreflectVarHandle

public VarHandle unreflectVarHandle(Field f) throws IllegalAccessException
Создаёт VarHandle, предоставляющий доступ к отражённому полю f типа T, объявленному в классе типа R. Тип переменной VarHandle — T. Если поле не статическое, у VarHandle есть один тип координаты R. В противном случае поле статическое, и у VarHandle нет типов координат.

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

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

Некоторые режимы доступа возвращаемого VarHandle не поддерживаются в следующих условиях:

  • если поле объявлено final, то режимы записи, атомного обновления, атомного числового обновления и атомного побитового обновления не поддерживаются.
  • если тип поля отличается от byte, short, char, int, long, float или double, то режимы атомного числового обновления не поддерживаются.
  • если тип поля отличается от boolean, byte, short, char, int или long, то режимы атомного побитового обновления не поддерживаются.

Если поле объявлено volatile, возвращаемый VarHandle переопределит доступ к полю (эффективно проигнорирует объявление volatile) в соответствии с его указанными режимами доступа.

Если тип поля — float или double, то режимы числового и атомного обновления сравнивают значения, используя их двоичное представление (см. Float.floatToRawIntBits(float) и Double.doubleToRawLongBits(double) соответственно).

API Note:
Побитовое сравнение значений float или double, выполняемое режимами числового и атомного обновления, отличается от оператора примитивного == и методов Float.equals(java.lang.Object) и Double.equals(java.lang.Object), особенно в отношении сравнения значений NaN или сравнения -0.0 с +0.0. Следует проявлять осторожность при выполнении операции сравнения и установки или сравнения и обмена с такими значениями, так как операция может неожиданно завершиться неудачей. В Java существует множество возможных значений NaN, которые считаются NaN в Java, хотя ни одна операция с плавающей точкой IEEE 754, предоставляемая Java, не может их различить. Отказ от операции может произойти, если ожидаемое или наблюдаемое значение является значением NaN, и оно преобразуется (возможно, платформозависимым способом) в другое значение NaN и, следовательно, имеет другое двоичное представление (см. Float.intBitsToFloat(int) или Double.longBitsToDouble(long) для получения дополнительной информации). Значения -0.0 и +0.0 имеют разные двоичные представления, но считаются равными при использовании оператора примитива ==. Отказ от операции может произойти, например, если числовой алгоритм вычисляет ожидаемое значение, скажем, -0.0, и ранее вычислил наблюдаемое значение, скажем, +0.0.
Параметры:
f - отражённое поле с типом поля T и классом объявления типа R
Возвращает:
VarHandle, предоставляющий доступ к полям, не являющимся статическими, или к статическому полю
Исключения:
IllegalAccessException - если проверка доступа завершается неудачей
NullPointerException - если аргумент имеет значение null
С:
9

revealDirect

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

hasPrivateAccess

@Deprecated(since="14") public boolean hasPrivateAccess()
Устарело.
Этот метод изначально был разработан для проверки доступа PRIVATE, который подразумевает полномочия доступа, но доступ MODULE с тех пор стал независимым от доступа PRIVATE. Рекомендуется вызывать hasFullPrivilegeAccess() вместо этого.
Возвращает true, если у этого объекта поиска есть доступ PRIVATE и MODULE.
Возвращает:
true если у этого объекта поиска есть доступ PRIVATE и MODULE.
С:
9

hasFullPrivilegeAccess

public boolean hasFullPrivilegeAccess()
Возвращает true, если у этого объекта поиска есть полный доступ с привилегиями, т.е. доступ PRIVATE и MODULE. Объект Lookup должен иметь полный доступ с привилегиями, чтобы получить доступ ко всем членам, разрешённым классу поиска lookup class.
Возвращает:
true если у этого объекта поиска есть полный доступ с привилегиями.
С:
14
См. также:
  • доступ к модулям и частным элементам

© 1993, 2021, 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.
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html

Spec-Zone.ru

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