Класс MethodHandles.Lookup
- Включающий класс:
MethodHandles
public static final class MethodHandles.Lookup extends Object
Класс lookup, которому требуется создать обработчик метода, вызовет MethodHandles.lookup, чтобы создать фабрику для себя. При создании объекта фабрики Lookup идентификатор класса lookup определяется и безопасно сохраняется в объекте Lookup. Затем класс lookup (или его делегаты) могут использовать методы-фабрики в объекте Lookup для создания обработчиков методов для членов с проверкой доступа. Это включает все методы, конструкторы и поля, разрешенные классу lookup, даже закрытые.
Методы-фабрики Lookup
Методы-фабрики объектаLookup соответствуют всем основным случаям использования методов, конструкторов и полей. Каждый обработчик метода, созданный методом-фабрикой, функционально эквивалентен определённому поведению байткода. (Поведения байткода описаны в разделе 5.4.3.5 спецификации виртуальной машины Java.) Вот сводка соответствия между методами-фабриками и поведением полученных обработчиков методов: | выражение lookup | член | поведение байткода |
|---|---|---|
lookup.findGetter(C.class,"f",FT.class) | FT f; |
(T) this.f; |
lookup.findStaticGetter(C.class,"f",FT.class) |
staticFT f;
|
(FT) C.f; |
lookup.findSetter(C.class,"f",FT.class) | FT f; |
this.f = x; |
lookup.findStaticSetter(C.class,"f",FT.class) |
staticFT f;
|
C.f = arg; |
lookup.findVirtual(C.class,"m",MT) | T m(A*); |
(T) this.m(arg*); |
lookup.findStatic(C.class,"m",MT) |
staticT 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 в методах lookup. Тип метода MT составлен из возвращаемого типа T и последовательности типов аргументов A*. Конструктор также имеет последовательность типов аргументов A* и считается возвращающим новый созданный объект типа C. И MT, и тип поля FT документированы как параметр с именем type. Формальный параметр this обозначает самоссылку типа C; если он присутствует, то всегда является ведущим аргументом для вызова обработчика метода. (В случае некоторых protected членов this может быть ограничен типом до класса lookup; см. ниже.) Наименование arg обозначает все остальные аргументы обработчика метода. В примерах кода для API ядра отражения имя thisOrNull обозначает нулевую ссылку, если доступный метод или поле статическое, и this в противном случае. Имена aMethod, aField, и aConstructor обозначают рефлективные объекты, соответствующие заданным членам, объявленным в типе C. Поведение байткода для операции findClass — это загрузка константного класса, как если бы это делалось через ldc CONSTANT_Class. Поведение представляется не как обработчик метода, а напрямую как константа Class.
В случаях, когда заданный член имеет переменную арность (т.е. метод или конструктор), возвращаемый обработчик метода также будет иметь переменную арность. Во всех остальных случаях возвращаемый обработчик метода будет иметь фиксированную арность.
Обсуждение: Эквивалентность между обработчиками методов, полученных с помощью lookup, и базовыми членами класса и поведением байткода может нарушиться несколькими способами:
- Если
Cне доступен символически из загрузчика класса lookup, поиск может всё же завершиться успешно, даже если нет эквивалентного выражения Java или байткодовой константы. - Аналогично, если
TилиMTне доступны символически из загрузчика класса lookup, поиск может всё же завершиться успешно. Например, запросы дляMethodHandle.invokeExactиMethodHandle.invokeвсегда завершатся успешно, независимо от запрошенного типа. - Если установлен менеджер безопасности, он может запретить поиск по различным причинам (см. ниже). В отличие от этого, инструкция
ldcпо константеCONSTANT_MethodHandleне подлежит проверкам менеджера безопасности. - Если у искомого метода очень большая арность, создание обработчика метода может завершиться ошибкой
IllegalArgumentException, из-за того, что тип обработчика метода имеет слишком много параметров.
Проверка доступа
Проверки доступа применяются в методах-фабрикахLookup, когда создаётся обработчик метода. Это ключевое отличие от API ядра отражения, так как java.lang.reflect.Method.invoke выполняет проверку доступа для каждого вызывающего абонента при каждом вызове. Все проверки доступа начинаются с объекта Lookup, который сравнивает свой записанный класс lookup со всеми запросами на создание обработчиков методов. Единственный объект Lookup может использоваться для создания любого количества обработчиков методов с проверкой доступа, все из которых проверяются по отношению к одному классу lookup.
Объект Lookup может быть использован другими надёжными кодами, например, протоколом метаобъектов. Общий объект Lookup делегирует способность создавать обработчики методов для закрытых членов класса lookup. Даже если привилегированный код использует объект Lookup, проверка доступа ограничивается привилегиями исходного класса lookup.
Поиск может завершиться ошибкой, потому что содержащий класс недоступен для класса lookup, или потому что необходимый член класса отсутствует, или потому что необходимый член класса недоступен для класса lookup, или потому что объект lookup недостаточно надёжен для доступа к члену. В случае функции установщика поля для поля final, принуждение к постоянству обрабатывается как своего рода контроль доступа, и поиск завершится ошибкой, за исключением специальных случаев Lookup.unreflectSetter. В любом из этих случаев метод ReflectiveOperationException будет выброшен во время попытки поиска. Точный класс будет одним из следующих:
- NoSuchMethodException — если запрашивается метод, но его нет
- NoSuchFieldException — если запрашивается поле, но его нет
- IllegalAccessException — если член существует, но проверка доступа завершается неудачно
В общем случае, условия, при которых обработчик метода может быть получен с помощью lookup для метода M, не более жёсткие, чем условия, при которых класс lookup мог бы скомпилировать, проверить и разрешить вызов M. Там, где JVM могла бы вызвать исключения типа NoSuchMethodError, поиск обработчика метода, как правило, вызовет соответствующее проверяемое исключение, например NoSuchMethodException. И эффект вызова обработчика метода, полученного в результате поиска, точно эквивалентен выполнению скомпилированного, проверенного и разрешённого вызова M. Та же самая закономерность верна для полей и конструкторов.
Обсуждение: Проверки доступа применяются только к именованным и отражённым методам, конструкторам и полям. Другие методы создания обработчиков методов, такие как MethodHandle.asType, не требуют проверок доступа и используются независимо от любого объекта Lookup.
Если искомый член protected, применяются обычные правила JVM, включая требование, чтобы класс lookup находился в том же пакете, что и искомый член, или наследовал его. (См. спецификацию виртуальной машины Java, разделы 4.9.2, 5.4.3.5 и 6.4.) Кроме того, если искомый член — это нестатическое поле или метод в другом пакете, полученный обработчик метода может применяться только к объектам класса lookup или одного из его подклассов. Это требование выполняется за счёт сужения типа ведущего параметра this с C (который обязательно будет суперклассом класса lookup) до самого класса lookup.
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, которые имеют закрытый доступ к другим классам в том же пакете
Аналогично, поиск с доступом к модулю гарантирует, что исходный создатель поиска был членом того же модуля, что и класс поиска.
Закрытый и модульный доступ определяются независимо; поиск может иметь любой или оба или ни один. Поиск, который обладает обоими режимами доступа, считается обладающим полным правом доступа.
Поиск с исходным доступом гарантирует, что этот поиск создан исходным классом поиска и методом запуска, вызванным 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 в C в модуле 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, возвращённый privateLookupIn, имеет право определять классы в пакете времени выполнения T. Следует проявлять особую осторожность при открытии пакета для другого модуля, так как таким образом определённые классы имеют такие же права доступа, как и другие члены M2.
Проверки межмодульного доступа
Lookup с PUBLIC или с режимом UNCONDITIONAL разрешает доступ между модулями. Проверка доступа выполняется относительно класса поиска и предыдущего класса поиска, если он есть. Объект Lookup в режиме UNCONDITIONAL может получить доступ к общедоступному типу во всех модулях, если тип находится в пакете, который экспортирован безусловно.
Если у объекта Lookup по LC в M1 нет предыдущего класса поиска, поиск с режимом PUBLIC может получить доступ ко всем общедоступным типам в модулях, доступных для M1, и тип находится в пакете, который экспортирован хотя бы для M1.
Если у объекта Lookup по LC в M1 есть предыдущий класс поиска PLC по M0, поиск с режимом PUBLIC может получить доступ к пересечению всех общедоступных типов, доступных для M1 и всех общедоступных типов, доступных для M0. M0 считывает M1, поэтому набор доступных типов включает:
- безусловно экспортированные пакеты из
M1 - безусловно экспортированные пакеты из
M0еслиM1считываетM0 - безусловно экспортированные пакеты из третьего модуля
M2еслиM0иM1считываютM2 - квалифицированно экспортированные пакеты из
M1вM0 - квалифицированно экспортированные пакеты из
M0вM1еслиM1считываетM0 - квалифицированно экспортированные пакеты из третьего модуля
M2вM0иM1еслиM0иM1считываютM2
Режимы доступа
Таблица ниже показывает режимы доступа объектаLookup, созданного любым из следующих методов фабрики или преобразования: MethodHandles::lookupMethodHandles::publicLookupMethodHandles::privateLookupInLookup::inLookup::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() | U | |||||
PUB.in(D) другой модуль | U | |||||
PUB.in(D).in(E) третий модуль | U | |||||
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 обладает специальным свойством, называемым чувствительностью к вызывающему объекту. Метод, чувствительный к вызывающему объекту, может вести себя по-разному в зависимости от идентификатора его непосредственного вызывающего объекта.Если запрашивается обработчик методов для метода, чувствительного к вызывающему объекту, применяются общие правила для поведения байткода, но они учитывают класс поиска особым образом. Результирующий обработчик методов ведет себя так, как будто он был вызван инструкцией, содержащейся в классе поиска, чтобы чувствительный к вызывающему объекту метод определял класс поиска. (При этом вызывающий объект обработчика методов игнорируется.) Таким образом, в случае методов, чувствительных к вызывающему объекту, различные классы поиска могут привести к поведению обработчиков методов.
В случаях, когда объект поиска является publicLookup() или некоторым другим объектом поиска без исходного доступа, класс поиска игнорируется. В таких случаях обработчик методов чувствительного к вызывающему объекту создать невозможно, доступ запрещен, и поиск завершается с ошибкой IllegalAccessException.
Обсуждение: Например, метод, чувствительный к вызывающему объекту, Class.forName(x), может возвращать различные классы или генерировать различные исключения в зависимости от загрузчика классов класса, который его вызывает. Публичный поиск Class.forName завершится неудачей, поскольку нет разумного способа определить его поведение байткода.
Если приложение кэширует обработчики методов для широкого совместного использования, оно должно использовать publicLookup() для их создания. Если будет поиск Class.forName, он завершится неудачей, и приложение должно принять соответствующие меры в этом случае. Возможно, что последующий поиск, возможно, во время вызова метода инициализации, сможет включить конкретную идентичность вызывающего объекта, сделав метод доступным.
Функция MethodHandles.lookup чувствительна к вызывающему объекту, чтобы обеспечить надежную основу для поиска. Почти все остальные методы API JSR 292 полагаются на объекты поиска для проверки запросов на доступ.
Краткое описание вложенных классов
| Modifier and Type | Class | Description |
|---|---|---|
static enum |
MethodHandles.Lookup.ClassOption |
Набор параметров класса, определяющих, добавляется ли скрытый класс, созданный методом Lookup::defineHiddenClass, динамически в качестве нового члена к вложению класса поиска, и/или имеет ли скрытый класс сильную связь с загрузчиком классов, помеченным как его определяющий загрузчик. |
Краткое описание полей
| Modifier and Type | Field | Description |
|---|---|---|
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. |
Краткое описание методов
| Modifier and Type | Method | Description |
|---|---|---|
<T> Class |
accessClass |
Определяет, может ли к классу быть предоставлен доступ из контекста поиска, определенного этим объектом Lookup. |
MethodHandle |
bind |
Создает метод-обработчик с ранней привязкой для нестатического метода. |
Class |
defineClass |
Создаёт и связывает класс или интерфейс из bytes, с тем же загрузчиком классов и в том же пакете выполнения и домене защиты, что и класс поиска этого поиска, как если бы вызывался ClassLoader::defineClass. |
MethodHandles.Lookup |
defineHiddenClass |
Создаёт скрытый класс или интерфейс из bytes, возвращая Lookup для нового созданного класса или интерфейса. |
MethodHandles.Lookup |
defineHiddenClassWithClassData |
Создаёт скрытый класс или интерфейс из bytes с сопутствующими данными класса class data, возвращая Lookup для нового созданного класса или интерфейса. |
MethodHandles.Lookup |
dropLookupMode |
Создаёт поиск в том же классе поиска, который этот объект поиска находит члены, но с режимом поиска, потерявшим данный режим поиска. |
<T> Class |
ensureInitialized |
Убеждается, что targetClass был инициализирован. |
Class |
findClass |
Ищет класс по имени из контекста поиска, определённого этим объектом Lookup, как будто разрешён инструкцией ldc. |
MethodHandle |
findConstructor |
Создаёт метод-обработчик, который создаёт объект и инициализирует его, используя конструктор указанного типа. |
MethodHandle |
findGetter |
Создаёт метод-обработчик, предоставляющий доступ для чтения к нестатическому полю. |
MethodHandle |
findSetter |
Создаёт метод-обработчик, предоставляющий доступ для записи к нестатическому полю. |
MethodHandle |
findSpecial |
Создаёт метод-обработчик с ранней привязкой для виртуального метода. |
MethodHandle |
findStatic |
Создаёт метод-обработчик для статического метода. |
MethodHandle |
findStaticGetter |
Создаёт метод-обработчик, предоставляющий доступ для чтения к статическому полю. |
MethodHandle |
findStaticSetter |
Создаёт метод-обработчик, предоставляющий доступ для записи к статическому полю. |
VarHandle |
findStaticVarHandle |
Создаёт VarHandle, предоставляющий доступ к статическому полю name типа type объявленному в классе типа decl. |
VarHandle |
findVarHandle |
Создаёт VarHandle, предоставляющий доступ к нестатическому полю name типа type объявленному в классе типа recv. |
MethodHandle |
findVirtual |
Создаёт метод-обработчик для виртуального метода. |
boolean |
hasFullPrivilegeAccess() |
Возвращает true, если у этого поиска есть полный привилегированный доступ, т.е. |
boolean |
hasPrivateAccess() |
Устарело. |
MethodHandles.Lookup |
in |
Создаёт поиск в указанном новом классе поиска. |
Class |
lookupClass() |
Указывает, какой класс выполняет поиск. |
int |
lookupModes() |
Указывает, какие классы защиты доступа к членам может производить этот объект поиска. |
Class |
previousLookupClass() |
Сообщает о классе поиска в другом модуле, из которого этот объект поиска был ранее телепортирован, или null. |
MethodHandleInfo |
revealDirect |
Разбирает прямой метод-обработчик, созданный этим объектом поиска или аналогичным ему. |
String |
toString() |
Отображает имя класса, из которого должны выполняться поиски, за которым следует "/" и имя предыдущего класса поиска, если он есть. |
MethodHandle |
unreflect |
Создаёт прямой метод-обработчик для m, если класс поиска имеет разрешение. |
MethodHandle |
unreflectConstructor |
Создаёт метод-обработчик для отражённого конструктора. |
MethodHandle |
unreflectGetter |
Создаёт метод-обработчик, предоставляющий доступ для чтения к отражённому полю. |
MethodHandle |
unreflectSetter |
Создаёт метод-обработчик, предоставляющий доступ для записи к отражённому полю. |
MethodHandle |
unreflectSpecial |
Создаёт метод-обработчик для отражённого метода. |
VarHandle |
unreflectVarHandle |
Создаёт VarHandle, предоставляющий доступ к отражённому полю f типа T объявленному в классе типа R. |
Подробное описание полей
PUBLIC
public static final int PUBLIC
public, который может повлиять на результат lookupModes. Значение, 0x01, совпадает со значением бита модификатора public PUBLIC. Объект с этим режимом поиска выполняет проверку доступа между модулями относительно класса поиска и предыдущего класса поиска, если они присутствуют.
- См. также:
PRIVATE
public static final int PRIVATE
private, который может повлиять на результат lookupModes. Значение, 0x02, совпадает со значением бита модификатора private PRIVATE.- См. также:
PROTECTED
public static final int PROTECTED
protected, который может повлиять на результат lookupModes. Значение, 0x04, совпадает со значением бита модификатора protected PROTECTED.- См. также:
PACKAGE
public static final int PACKAGE
package (доступ по умолчанию), который может повлиять на результат lookupModes. Значение — 0x08, которое не соответствует напрямую ни одному биту модификатора модификатора.- См. также:
MODULE
public static final int MODULE
module, который может повлиять на результат lookupModes. Значение — 0x10, которое не соответствует напрямую ни одному биту модификатора модификатора. В сочетании с битом модификатора PUBLIC, объект Lookup с этим режимом поиска может получить доступ ко всем общедоступным типам в модуле класса поиска и общедоступным типам в пакетах, экспортированных другими модулями в модуль класса поиска. Если этот режим поиска установлен, предыдущий класс поиска всегда null.
- С:
- 9
- См. также:
БЕЗУСЛОВНЫЙ
public static final int UNCONDITIONAL
unconditional, который может повлиять на результат lookupModes. Значение — 0x20, которое не соответствует напрямую ни одному биту модификатора модификатора. Объект Lookup с этим режимом поиска предполагает читаемость. Этот режим поиска может получить доступ ко всем общедоступным членам общедоступных типов всех модулей, когда тип находится в пакете, который exported unconditionally. Если этот режим поиска установлен, предыдущий класс поиска всегда null.
- С:
- 9
- См. также:
ИСТОЧНИК
public static final int ORIGINAL
original, который может повлиять на результат lookupModes. Значение — 0x40, которое не соответствует напрямую ни одному биту модификатора модификатора. Если этот режим поиска установлен, объект Lookup должен быть создан исходным классом поиска вызовом метода MethodHandles.lookup() или методом запуска, вызванным JVM. Объект Lookup с этим режимом поиска имеет полный привилегированный доступ.
- С:
- 16
- См. также:
Подробное описание методов
lookupClass
public Class<?> lookupClass()
Если у этого объекта поиска есть предыдущий класс поиска, проверки доступа выполняются относительно как класса поиска, так и предыдущего класса поиска.
Класс подразумевает максимальный уровень разрешений доступа, но разрешения могут быть дополнительно ограничены битовой маской lookupModes, которая управляет возможностью доступа к не общедоступным членам.
- Возвращает:
- класс поиска, от имени которого этот объект поиска находит члены
- См. также:
previousLookupClass
public Class<?> previousLookupClass()
null. Объект поиска, созданный фабричными методами, такими как lookup() и publicLookup(), имеет null предыдущий класс поиска. Объект поиска имеет непустой предыдущий класс поиска, когда этот поиск был перенесен из старого класса поиска в одном модуле в новый класс поиска в другом модуле.
- Возвращает:
- класс поиска в другом модуле, из которого этот объект поиска был ранее перенесен, или
null - С:
- 14
- См. также:
lookupModes
public int lookupModes()
Свежесозданный объект поиска в классе вызывающей стороны имеет все возможные биты установленные, за исключением UNCONDITIONAL. Объект поиска нового класса поиска созданный из предыдущего объекта поиска может иметь некоторые биты режима установленные в ноль. Биты режима также могут быть непосредственно сброшены. После сброса биты режима не могут быть восстановлены из пониженного объекта поиска. Цель состоит в ограничении доступа через новый объект поиска, чтобы он мог получить доступ только к именам, которые могут быть доступны исходному объекту поиска, а также новому классу поиска.
- Возвращает:
- режимы поиска, ограничивающие типы доступа, выполняемые этим объектом поиска
- См. также:
в
public MethodHandles.Lookup in(Class<?> requestedLookupClass)
lookupClass. Однако, результирующий Lookup объект гарантированно не будет иметь больше доступа, чем исходный. В частности, доступ может быть утрачен следующим образом:
- Если новый класс поиска отличается от старого класса поиска, т.е. доступ
ORIGINALтеряется. - Если новый класс поиска находится в другом модуле, чем старый, т.е. доступ
MODULEтеряется. - Если новый класс поиска находится в другом пакете, чем старый, члены protected и default (пакета) не будут доступны, т.е. доступ
PROTECTEDиPACKAGEтеряются. - Если новый класс поиска не находится в том же пакете, что и старый, частные члены не будут доступны, а защищённые члены не будут доступны в силу наследования, т.е. доступ
PRIVATEтеряется. (Защищённые члены могут оставаться доступными из-за совместного использования пакета.) - Если новый класс поиска не доступен для этого поиска, тогда никакие члены, даже публичные, не будут доступны, т.е. все режимы доступа теряются.
- Если новый класс поиска, старый класс поиска и предыдущий класс поиска все находятся в разных модулях, т.е. перемещение в третий модуль, все режимы доступа теряются.
Новый предыдущий класс поиска выбирается следующим образом:
- Если новый объект поиска имеет
UNCONDITIONALбит, новый предыдущий класс поиска —null. - Если новый класс поиска находится в том же модуле, что и старый класс поиска, новый предыдущий класс поиска — старый предыдущий класс поиска.
- Если новый класс поиска находится в другом модуле, чем старый класс поиска, новый предыдущий класс поиска — старый класс поиска.
Возможности результирующего поиска для загрузки классов (используемые во время вызовов findClass(java.lang.String)) определяются загрузчиком класса поиска, который может измениться в результате этой операции.
- Параметры:
-
requestedLookupClass- желаемый класс поиска для нового объекта поиска - Возвращает:
- объект поиска, который указывает на желаемый класс поиска, или тот же объект, если изменений нет
- Изучает:
-
IllegalArgumentException- еслиrequestedLookupClass— это примитивный тип или void или класс массива -
NullPointerException- если аргумент равен null - См. также:
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:
- Поиск с режимом
PACKAGEно без режимаPRIVATEможет безопасно делегировать доступ к непубличным членам в пакете класса поиска без предоставления частного доступа. Поиск с режимомMODULEно без режимаPACKAGEможет безопасно делегироватьPUBLICдоступ в модуле класса поиска без предоставления доступа к пакету. Поиск с предыдущим классом поиска (и режимомPUBLICно без режимаMODULE) может безопасно делегировать доступ к публичным классам, доступным как модулю класса поиска, так и модулю предыдущего класса поиска. - Параметры:
-
modeToDrop- режим поиска, который нужно удалить - Возвращает:
- объект поиска, в котором отсутствует указанный режим, или тот же объект, если изменений нет
- Изучает:
-
IllegalArgumentException- еслиmodeToDropне является одним изPUBLIC,MODULE,PACKAGE,PROTECTED,PRIVATE,ORIGINALилиUNCONDITIONAL - С:
- 9
- См. также:
defineClass
public Class<?> defineClass(byte[] bytes) throws IllegalAccessException
bytes с тем же загрузчиком классов и в том же пакете среды выполнения и домене защиты, что и класс поиска этого поиска, как если бы вызывался ClassLoader::defineClass. Режимы поиска для этого поиска должны включать доступ PACKAGE по умолчанию (члены пакета будут доступны классу). Режим поиска PACKAGE служит для аутентификации того, что объект поиска был создан вызывающим объектом в пакете среды выполнения (или получен из поиска, изначально созданного кодом с соответствующими привилегиями, для целевого класса в пакете среды выполнения).
Параметр bytes — это байты класса действительного файла класса (как определено в Спецификации Java Virtual Machine) с именем класса в том же пакете, что и класс поиска.
Этот метод не запускает инициализатор класса. Инициализатор класса может быть запущен впоследствии, как подробно описано в разделе 12.4 Спецификации языка Java.
Если есть диспетчер безопасности, и у этого поиска нет полного доступа с привилегиями, его метод checkPermission сначала вызывается для проверки RuntimePermission("defineClass").
- Параметры:
-
bytes- байты класса - Возвращает:
- объект
Classдля класса - Изучает:
-
IllegalAccessException- если у этого поиска нет доступаPACKAGE -
ClassFormatError- еслиbytesне является структуройClassFile -
IllegalArgumentException- еслиbytesобозначает класс в другом пакете, чем класс поиска, илиbytesне является классом или интерфейсом (флагACC_MODULEустановлен в значении элементаaccess_flags) -
VerifyError- если созданный класс не может быть проверен -
LinkageError- если созданный класс не может быть связан по какой-либо другой причине -
SecurityException- если диспетчер безопасности присутствует и он отказывает в доступе -
NullPointerException- еслиbytes—null - С:
- 9
- См. также:
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 формате файла, используя следующие правила:
- Режимы поиска (режимы поиска) для этого
Lookupдолжны включать доступ с полными привилегиями (полные привилегии). Этот уровень доступа необходим для созданияCв модуле класса поиска данногоLookup. - Предполагаемое представление в
bytesдолжно быть структуройClassFile(JVMS 4.1) поддерживаемой основной и дополнительной версии. Основная и дополнительная версия могут отличаться от версии файлаclassкласса поиска данногоLookup. - Значение
this_classдолжно быть корректным индексом в таблицеconstant_pool, а запись по этому индексу должна быть корректной структуройCONSTANT_Class_info. ПустьNбудет двоичным именем, закодированным во внутреннем формате, которое указано в этой структуре.Nдолжно обозначать класс или интерфейс в том же пакете, что и класс поиска. - Пусть
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считается имеющим тот же runtime пакет, модуль и домен защиты, что и класс поиска этого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
- См. также:
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:
- Фреймворк может создать скрытый класс с данными класса с одним или несколькими объектами и загрузить данные класса как динамически вычисляемые константы через метод bootstrap.
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
- См. также:
toString
public String toString()
Class.getName.) Если существуют ограничения на доступ к этому поиску, это указывается добавлением суффикса к имени класса, состоящего из косой черты и ключевого слова. Ключевое слово представляет собой наиболее строгий разрешенный доступ и выбирается следующим образом: - Если доступ не разрешен, суффикс — «/noaccess».
- Если разрешен только безусловный доступ, суффикс — «/publicLookup».
- Если разрешен только публичный доступ к типам в экспортированных пакетах, суффикс — «/public».
- Если разрешен только публичный и модульный доступ, суффикс — «/module».
- Если разрешен публичный и пакетный доступ, суффикс — «/package».
- Если разрешен публичный, пакетный и приватный доступ, суффикс — «/private».
MethodHandles.lookup. Объекты, созданные с помощью Lookup.in, всегда имеют ограниченный доступ и отображают суффикс. (Может показаться странным, что защищенный доступ сильнее, чем приватный. При рассмотрении независимо от пакетного доступа, защищенный доступ — первый, который теряется, поскольку он требует прямой связи между подклассами вызывающей и вызываемой сторон.)
- Overrides:
-
toStringв классеObject - Возвращает:
- строковое представление объекта.
- См. также:
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, пытается найти и загрузить класс, а затем определяет, доступен ли класс для этого объекта поиска. Для класса или интерфейса имя является бинарным именем. Для класса массива с n измерениями имя начинается с n вхождений '[' и продолжается типом элемента, закодированным в таблице, указанной в Class.getName().
Контекст поиска здесь определяется классом поиска, его загрузчиком классов и режимами поиска.
- Параметры:
-
targetName- бинарное имя класса или строка, представляющая класс массива - Возвращает:
- запрашиваемый класс.
- Исключения:
-
SecurityException- если менеджер безопасности присутствует и он отказывает в доступе -
LinkageError- если проверка связности не удалась -
ClassNotFoundException- если класс не может быть загружен загрузчиком класса поиска. -
IllegalAccessException- если класс недоступен с использованием разрешенных режимов доступа. -
NullPointerException- еслиtargetNameимеет значение null - См. Спецификацию виртуальной машины Java:
- 5.4.3.1 Разрешение класса и интерфейса
- С:
- 9
ensureInitialized
public <T> Class<T> ensureInitialized(Class<T> targetClass) throws IllegalAccessException
targetClass был инициализирован. Класс, который должен быть инициализирован, должен быть доступен для этого объекта Lookup. Этот метод вызывает инициализацию targetClass, если она ещё не была выполнена, как указано в JVMS 5.5. Этот метод возвращает, когда targetClass полностью инициализирован или когда targetClass инициализируется текущей нитью.
- Type Parameters:
-
T- тип класса, который должен быть инициализирован - Parameters:
-
targetClass- класс, который должен быть инициализирован - Returns:
-
targetClass, который был инициализирован или который инициализируется текущей нитью. - Throws:
-
IllegalArgumentException- еслиtargetClassявляется примитивным типом или классом массива или массива -
IllegalAccessException- еслиtargetClassнедоступен для этого поиска -
ExceptionInInitializerError- если инициализация класса, вызванная этим методом, завершилась неудачей -
SecurityException- если присутствует менеджер безопасности, и он отклоняет доступ - См. Спецификацию виртуальной машины Java:
- 5.5 Инициализация
- С:
- 15
accessClass
public <T> Class<T> accessClass(Class<T> targetClass) throws IllegalAccessException
Lookup. Статический инициализатор класса не выполняется. Если targetClass является классом массива, targetClass является доступным, если тип элемента класса массива является доступным. В противном случае targetClass определяется как доступный следующим образом. Если targetClass находится в том же модуле, что и класс поиска, класс поиска LC в модуле M1, а предыдущий класс поиска находится в модуле M0 или null, если он не указан, targetClass доступен, если и только если истинно одно из следующих условий:
- Если у этого поиска есть
PRIVATEдоступ,targetClassявляетсяLCили другим классом в том же вложенном набореLC. - Если у этого поиска есть
PACKAGEдоступ,targetClassнаходится в той же среде выполнения пакетеLC. - Если у этого поиска есть
MODULEдоступ,targetClassявляется типом public вM1. - Если у этого поиска есть
PUBLICдоступ,targetClassявляется типом public в пакете, экспортированном модулемM1по крайней мере вM0, если присутствует предыдущий класс поиска; в противном случаеtargetClassявляется типом public в пакете, экспортированномM1безусловно.
В противном случае, если у этого поиска есть UNCONDITIONAL доступ, этот поиск может получить доступ к типам public во всех модулях, когда тип находится в пакете, который экспортирован безусловно.
В противном случае, targetClass находится в другом модуле, отличном от lookupClass, и если у этого поиска нет PUBLIC доступа, lookupClass недоступен.
В противном случае, если у этого поиска нет предыдущего класса поиска, M1 является модулем, содержащим lookupClass, а M2 является модулем, содержащим targetClass, тогда targetClass является доступным, если и только если
-
M1считываетM2, и -
targetClassявляется public и находится в пакете, экспортированномM2по крайней мере вM1.
В противном случае, если у этого поиска есть предыдущий класс поиска, M1 и M2 такие же, как и раньше, а M0 является модулем, содержащим предыдущий класс поиска, то targetClass доступен, если и только если истинно одно из следующих утверждений:
-
targetClassнаходится вM0иM1считываетM0, и тип находится в пакете, экспортированном в по крайней мереM1. -
targetClassнаходится вM1иM0считываетM1, и тип находится в пакете, экспортированном в по крайней мереM0. -
targetClassнаходится в третьем модулеM2иM0иM1считываютM2, и тип находится в пакете, экспортированном по крайней мере вM0иM2.
В противном случае targetClass недоступен.
- Type Parameters:
-
T- тип класса, для которого проверяется доступ - Parameters:
-
targetClass- класс, для которого проверяется доступ - Returns:
-
targetClass, для которого проверка доступа была выполнена - Throws:
-
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
- Parameters:
-
refc- класс или интерфейс, из которого осуществляется доступ к методу -
name- имя метода (которое не должно быть "<init>") -
type- тип метода, без аргумента получателя -
specialCaller- предлагаемый вызывающий класс для выполненияinvokespecial - Returns:
- требуемый обработчик метода
- Throws:
-
NoSuchMethodException- если метод не существует -
IllegalAccessException- если проверка доступа завершилась неудачей, или если метод являетсяstatic, или если бит переменной арности метода установлен, иasVarargsCollectorзавершился неудачей -
SecurityException- если присутствует менеджер безопасности, и он отклоняет доступ -
NullPointerException- если какой-либо аргумент равен null
findGetter
public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
- Parameters:
-
refc- класс или интерфейс, из которого осуществляется доступ к методу -
name- имя поля -
type- тип поля - Returns:
- обработчик метода, который может загружать значения из поля
- Throws:
-
NoSuchFieldException- если поле не существует -
IllegalAccessException- если проверка доступа завершилась неудачей, или если поле являетсяstatic -
SecurityException- если присутствует менеджер безопасности, и он отклоняет доступ -
NullPointerException- если какой-либо аргумент равен null - См. также:
findSetter
public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
- Parameters:
-
refc- класс или интерфейс, из которого осуществляется доступ к методу -
name- имя поля -
type- тип поля - Returns:
- обработчик метода, который может сохранять значения в поле
- Throws:
-
NoSuchFieldException- если поле не существует -
IllegalAccessException- если проверка доступа завершилась неудачей, или если поле являетсяstaticилиfinal -
SecurityException- если присутствует менеджер безопасности, и он отклоняет доступ -
NullPointerException- если какой-либо аргумент равен null - См. также:
findVarHandle
public VarHandle findVarHandle(Class<?> recv, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
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:
- Битовое сравнение значений
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. - Параметры:
-
recv- класс получателя типаR, в котором объявлено нестатическое поле -
name- имя поля -
type- тип поля типаT - Возвращает:
- VarHandle, обеспечивающий доступ к нестатическим полям.
- Исключения:
-
NoSuchFieldException- если поле не существует -
IllegalAccessException- если проверка доступа завершается неудачей или если поле являетсяstatic -
SecurityException- если присутствует менеджер безопасности и он отказывается предоставить доступ -
NullPointerException- если какой-либо аргумент равен null - См. также:
- 9
findStaticGetter
public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
Если вызывается возвращённый обработчик метода, класс поля будет инициализирован, если он ещё не был инициализирован.
- Параметры:
-
refc- класс или интерфейс, из которого осуществляется доступ к методу -
name- имя поля -
type- тип поля - Возвращает:
- обработчик метода, который может загружать значения из поля
- Исключения:
-
NoSuchFieldException- если поле не существует -
IllegalAccessException- если проверка доступа завершается неудачей, или если поле не являетсяstatic -
SecurityException- если присутствует менеджер безопасности и он отказывается предоставить доступ -
NullPointerException- если какой-либо аргумент равен null
findStaticSetter
public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
Если вызывается возвращённый обработчик метода, класс поля будет инициализирован, если он ещё не был инициализирован.
- Параметры:
-
refc- класс или интерфейс, из которого осуществляется доступ к методу -
name- имя поля -
type- тип поля - Возвращает:
- обработчик метода, который может сохранять значения в поле
- Исключения:
-
NoSuchFieldException- если поле не существует -
IllegalAccessException- если проверка доступа завершается неудачей, или если поле не являетсяstaticили являетсяfinal -
SecurityException- если присутствует менеджер безопасности и он отказывается предоставить доступ -
NullPointerException- если какой-либо аргумент равен null
findStaticVarHandle
public VarHandle findStaticVarHandle(Class<?> decl, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
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:
- Битовое сравнение значений
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. - Параметры:
-
decl- класс, в котором объявлено статическое поле -
name- имя поля -
type- тип поля типаT - Возвращает:
- VarHandle, обеспечивающий доступ к статическому полю
- Исключения:
-
NoSuchFieldException- если поле не существует -
IllegalAccessException- если проверка доступа завершается неудачей или если поле не являетсяstatic -
SecurityException- если присутствует менеджер безопасности и он отказывается предоставить доступ -
NullPointerException- если какой-либо аргумент равен null - См. также:
- 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 классом поиска.)- Параметры:
-
receiver- объект, из которого осуществляется доступ к методу -
name- имя метода -
type- тип метода, с опущенным аргументом получателя - Возвращает:
- необходимый обработчик метода
- Исключения:
-
NoSuchMethodException- если метод не существует -
IllegalAccessException- если проверка доступа завершается неудачно или если бит модификатора переменной арности метода установлен, иasVarargsCollectorзавершается неудачно -
SecurityException- если менеджер безопасности присутствует и он отказывается предоставить доступ -
NullPointerException- если любой аргумент равен null - См. также:
unreflect
public MethodHandle unreflect(Method m) throws IllegalAccessException
accessible метода не установлен, проверка доступа выполняется немедленно от имени класса поиска. Если m не является общедоступным, не следует передавать полученный обработчик недоверенным сторонам. Возвращаемый обработчик метода будет иметь переменную арность тогда и только тогда, когда бит модификатора переменной арности метода (0x0080) установлен.
Если m статический, и если вызван возвращаемый обработчик метода, класс метода будет инициализирован, если он ещё не был инициализирован.
- Параметры:
-
m- отражённый метод - Возвращает:
- обработчик метода, который может вызвать отражённый метод
- Исключения:
-
IllegalAccessException- если проверка доступа завершается неудачно или если бит модификатора переменной арности метода установлен, иasVarargsCollectorзавершается неудачно -
NullPointerException- если аргумент равен null
unreflectSpecial
public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException
invokespecial внутри явно указанного specialCaller. Тип обработчика метода будет таким же, как у метода, с соответствующим ограниченным типом получателя. (Тип получателя будет specialCaller или подтип.) Если флаг accessible метода не установлен, проверка доступа выполняется немедленно от имени класса поиска, как если бы выполнялась инструкция invokespecial. Перед разрешением метода, если явно указанный класс вызывающего метода не идентичен классу поиска, или если у этого объекта поиска нет привилегий частного доступа, доступ не разрешается.
Возвращаемый обработчик метода будет иметь переменную арность тогда и только тогда, когда бит модификатора переменной арности метода (0x0080) установлен.
- Параметры:
-
m- отражённый метод -
specialCaller- класс, номинально вызывающий метод - Возвращает:
- обработчик метода, который может вызвать отражённый метод
- Исключения:
-
IllegalAccessException- если проверка доступа завершается неудачно, или если метод являетсяstatic, или если бит модификатора переменной арности метода установлен, иasVarargsCollectorзавершается неудачно -
NullPointerException- если любой аргумент равен null
unreflectConstructor
public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException
newInstance, создавая новый экземпляр класса конструктора по аргументам, переданным обработчику метода. Если флаг accessible конструктора не установлен, проверка доступа выполняется немедленно от имени класса поиска.
Возвращаемый обработчик метода будет иметь переменную арность тогда и только тогда, когда бит модификатора переменной арности конструктора (0x0080) установлен.
Если вызван возвращаемый обработчик метода, класс конструктора будет инициализирован, если он ещё не был инициализирован.
- Параметры:
-
c- отражённый конструктор - Возвращает:
- обработчик метода, который может вызвать отражённый конструктор
- Исключения:
-
IllegalAccessException- если проверка доступа завершается неудачно или если бит модификатора переменной арности метода установлен, иasVarargsCollectorзавершается неудачно -
NullPointerException- если аргумент равен null
unreflectGetter
public MethodHandle unreflectGetter(Field f) throws IllegalAccessException
static, обработчик метода не будет принимать аргументы. В противном случае единственным аргументом будет экземпляр, содержащий поле. Если флаг Field объекта accessible не установлен, проверка доступа выполняется немедленно от имени класса поиска. Если поле является статическим, и если вызван возвращаемый обработчик метода, класс поля будет инициализирован, если он ещё не был инициализирован.
- Параметры:
-
f- отражённое поле - Возвращает:
- обработчик метода, который может загружать значения из отражённого поля
- Исключения:
-
IllegalAccessException- если проверка доступа завершается неудачно -
NullPointerException- если аргумент равен null
unreflectSetter
public MethodHandle unreflectSetter(Field f) throws IllegalAccessException
static, обработчик метода будет принимать единственный аргумент типа значения поля, значение, которое должно быть сохранено. В противном случае два аргумента будут экземпляром, содержащим поле, и значением, которое должно быть сохранено. Если флаг Field объекта accessible не установлен, проверка доступа выполняется немедленно от имени класса поиска. Если поле является final, доступ на запись не будет разрешён, и проверка доступа завершится неудачно, за исключением некоторых узких обстоятельств, описанных в Field.set. Обработчик метода возвращается только если соответствующий вызов метода Field объекта set мог завершиться успешно. В частности, поля, которые являются одновременно static и final , могут никогда не быть установлены.
Если поле является static, и если вызван возвращаемый обработчик метода, класс поля будет инициализирован, если он ещё не был инициализирован.
- Параметры:
-
f- отражённое поле - Возвращает:
- обработчик метода, который может сохранять значения в отражённое поле
- Исключения:
-
IllegalAccessException- если проверка доступа завершается неудачно, или если поле являетсяfinalи доступ на запись не разрешён для объектаField -
NullPointerException- если аргумент равен null
unreflectVarHandle
public VarHandle unreflectVarHandle(Field f) throws IllegalAccessException
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:
- Двоичное сравнение значений
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. - Параметры:
-
f- отражённое поле, с полем типаT, и классом объявления типаR - Возвращает:
- VarHandle, предоставляющий доступ к нестатическим полям или статическому полю
- Исключения:
-
IllegalAccessException- если проверка доступа не удалась -
NullPointerException- если аргумент равен null - С:
- 9
revealDirect
public MethodHandleInfo revealDirect(MethodHandle target)
- Параметры:
-
target- прямой метод-обработчик для раскрытия в компоненты символической ссылки - Возвращает:
- символическая ссылка, которая может быть использована для восстановления этого метода-обработчика из этого объекта поиска
- Исключения:
-
SecurityException- если менеджер безопасности присутствует и он отклоняет доступ -
IllegalArgumentException- если цель не является прямым методом-обработчиком или если проверка доступа завершается неудачей -
NullPointerException- если цель —null - С:
- 1.8
- См. также:
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, 2023, 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/21/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html
PRIVATE, который подразумевает полный привилегированный доступ, но доступMODULEс тех пор стал независимым от доступаPRIVATE.