Класс MethodHandles.Lookup
- Внешний класс:
MethodHandles
public static final class MethodHandles.Lookup extends Object
Класс поиска, которому необходимо создавать дескрипторы методов, вызывает MethodHandles.lookup, чтобы создать фабрику для себя. При создании объекта фабрики Lookup определяется идентификатор класса поиска, который безопасно сохраняется в объекте Lookup. Затем класс поиска (или его делегаты) может использовать фабричные методы объекта Lookup для создания дескрипторов методов для членов, доступ к которым проверяется. Сюда входят все методы, конструкторы и поля, доступные классу поиска, в том числе закрытые.
Фабричные методы поиска
Фабричные методы объектаLookup соответствуют всем основным сценариям использования методов, конструкторов и полей. Каждый дескриптор метода, созданный фабричным методом, функционально эквивалентен определённому поведению байт-кода. (Поведение байт-кода описано в разделе 5.4.3.5 спецификации виртуальной машины Java.) Ниже приведена сводка соответствия между этими фабричными методами и поведением получаемых дескрипторов методов: | выражение поиска | член | поведение байт-кода |
|---|---|---|
lookup.findGetter(C.class,"f",FT.class) | FT f; |
(FT) 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. Тип метода MT состоит из типа возвращаемого значения T и последовательности типов аргументов A*. Конструктор также имеет последовательность типов аргументов A* и считается возвращающим вновь созданный объект типа C. И MT, и тип поля FT документируются как параметр с именем type. Формальный параметр this обозначает ссылку на самого себя типа C; если он присутствует, то всегда является первым аргументом вызова дескриптора метода. (Для некоторых членов protected тип this может быть ограничен классом поиска; см. ниже.) Имя arg обозначает все остальные аргументы дескриптора метода. В примерах кода для API Core Reflection имя thisOrNull обозначает ссылку null, если вызываемый метод или поле является статическим, и this в противном случае. Имена aMethod, aField и aConstructor обозначают отражательные объекты, соответствующие указанным членам, объявленным в типе C. Поведение байт-кода для операции findClass — это загрузка константного класса, как при помощи ldc CONSTANT_Class. Это поведение представлено не дескриптором метода, а непосредственно константой Class.
Если указанный член имеет переменную арность (то есть является методом или конструктором), возвращённый дескриптор метода также будет иметь переменную арность. Во всех остальных случаях возвращённый дескриптор метода будет иметь фиксированную арность.
Обсуждение: Эквивалентность найденных дескрипторов методов, соответствующих членов класса и поведений байт-кода может нарушаться в нескольких случаях:
- Если
Cнедоступен для символьного доступа из загрузчика класса поиска, поиск всё равно может завершиться успешно, даже если эквивалентного выражения Java или константы байт-кода не существует. - Аналогично, поиск всё равно может завершиться успешно, если
TилиMTнедоступен для символьного доступа из загрузчика класса поиска. Например, поискMethodHandle.invokeExactиMethodHandle.invokeвсегда завершается успешно независимо от запрошенного типа. - Если у найденного метода очень большая арность, создание дескриптора метода может завершиться ошибкой
IllegalArgumentException, поскольку тип дескриптора метода содержит слишком много параметров.
Проверка доступа
В фабричных методахLookup проверка доступа выполняется при создании дескриптора метода. Это ключевое отличие от API Core Reflection, поскольку 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, включая требование, чтобы класс поиска находился в том же пакете, что и требуемый член, либо наследовал этот член. (См. разделы 4.9.2, 5.4.3.5 и 6.4 спецификации виртуальной машины Java.) Кроме того, если требуемый член является нестатическим полем или методом в другом пакете, полученный дескриптор метода можно применять только к объектам класса поиска или одного из его подклассов. Это требование обеспечивается сужением типа первого параметра this с C (который обязательно будет суперклассом класса поиска) до самого класса поиска.
JVM предъявляет аналогичное требование к инструкции invokespecial: аргумент-получатель должен соответствовать как разрешённому методу, так и текущему классу. И это требование обеспечивается сужением типа первого параметра полученного дескриптора метода. (См. раздел 4.10.1.9 спецификации виртуальной машины Java.)
JVM представляет конструкторы и блоки статической инициализации как внутренние методы со специальными именами ("<init>" и "<clinit>"). Внутренний синтаксис инструкций вызова позволяет ссылаться на такие внутренние методы, как на обычные методы, но верификатор байт-кода JVM их отклоняет. Поиск такого внутреннего метода приведёт к NoSuchMethodException.
Если связь между вложенными типами выражена непосредственно атрибутами NestHost и NestMembers (см. разделы 4.7.28 и 4.7.29 спецификации виртуальной машины Java), соответствующий объект 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, обладающих закрытым доступом к другим классам того же члена пакета
Аналогично, поиск с доступом к модулю гарантирует, что исходный создатель поиска был членом того же модуля, что и класс поиска.
Закрытый доступ и доступ к модулю — это независимые режимы, определяемые отдельно; поиск может обладать одним из них, обоими или ни одним. Поиск, обладающий обоими режимами доступа, называется поиском с полным привилегированным доступом.
Исходный доступ гарантирует, что поиск создан исходным классом поиска и методом начальной загрузки, вызванным виртуальной машиной. Такой поиск с исходным доступом также обладает закрытым доступом и доступом к модулю, а также следующими дополнительными возможностями:
- создание дескрипторов методов, вызывающих методы с учётом вызывающего кода, например
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 без прав доступа, а класс поиска D объекта lookup2 записывается как предыдущий класс поиска.
Перемещение между модулями ограничивает доступ открытыми типами, к которым в равной степени могут обращаться как класс поиска, так и предыдущий класс поиска (см. ниже).
Метод 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 — новым предыдущим классом поиска; объект Lookup, полученный в результате, теряет доступ MODULE. Полученный объект 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, созданного одним из следующих фабричных методов или методов преобразования: | Объект поиска | исходный | защищённый | закрытый | пакет | модуль | открытый |
|---|---|---|---|---|---|---|
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, все режимы доступа сбрасываются.
Методы, чувствительные к вызывающему коду
Небольшое число методов Java обладают особым свойством, называемым чувствительностью к вызывающему коду. Метод, чувствительный к вызывающему коду, может вести себя по-разному в зависимости от идентификатора своего непосредственного вызывающего кода.Если запрошен дескриптор метода для метода, чувствительного к вызывающему коду, применяются общие правила для поведения байт-кода, но они особым образом учитывают класс поиска. Полученный дескриптор метода ведёт себя так, как если бы он был вызван инструкцией, содержащейся в классе поиска, поэтому метод, чувствительный к вызывающему коду, распознаёт класс поиска. (В отличие от этого, вызывающий дескриптор метода игнорируется.) Поэтому в случае методов, чувствительных к вызывающему коду, разные классы поиска могут приводить к появлению дескрипторов методов с разным поведением.
Если объект поиска — это publicLookup() или какой-либо другой объект поиска без исходного доступа, класс поиска игнорируется. В таких случаях невозможно создать дескриптор метода, чувствительного к вызывающему коду, доступ запрещён, и поиск завершается с IllegalAccessException.
Обсуждение: Например, метод Class.forName(x), чувствительный к вызывающему коду, может возвращать разные классы или выбрасывать разные исключения в зависимости от загрузчика классов класса, который его вызывает. Общедоступный поиск Class.forName завершится неудачей, поскольку невозможно разумным образом определить поведение его байт-кода.
Если приложение кэширует дескрипторы методов для широкого совместного использования, ему следует создавать их с помощью publicLookup(). Поиск Class.forName завершится неудачей, и в этом случае приложение должно предпринять соответствующие действия. Возможно, последующий поиск, например во время вызова метода начальной загрузки, сможет учесть конкретный идентификатор вызывающего кода, сделав метод доступным.
Функция MethodHandles.lookup чувствительна к вызывающему коду, чтобы обеспечить безопасную основу для поисков. Почти все остальные методы API JSR 292 используют объекты поиска для проверки запросов доступа.
- С момента появления:
- 1.7
Краткое описание вложенных классов
| Модификатор и тип | Класс | Описание |
|---|---|---|
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. |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
<T> Class |
accessClass |
Определяет, доступен ли класс из контекста поиска, заданного этим объектом Lookup. |
MethodHandle |
bind |
Создаёт раннепривязанный дескриптор метода для нестатического метода. |
Class |
defineClass |
Создаёт и связывает класс или интерфейс из bytes с тем же загрузчиком классов, в том же пакете времени выполнения и домене защиты, что и класс поиска этого объекта поиска, как если бы был вызван ClassLoader::defineClass. |
MethodHandles.Lookup |
defineHiddenClass |
Создаёт скрытый класс или интерфейс из bytes и возвращает Lookup для только что созданного класса или интерфейса. |
MethodHandles.Lookup |
defineHiddenClassWithClassData |
Создаёт скрытый класс или интерфейс из bytes с соответствующими данными класса и возвращает 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 бита-модификатора. Lookup с этим режимом поиска выполняет проверку доступа между модулями относительно класса поиска и предыдущего класса поиска, если он есть.
- См. также:
PRIVATE
public static final int PRIVATE
private, который может влиять на результат lookupModes. Значение 0x02 случайно совпадает со значением private бита-модификатора.- См. также:
PROTECTED
public static final int PROTECTED
protected, который может влиять на результат lookupModes. Значение 0x04 случайно совпадает со значением protected бита-модификатора.- См. также:
PACKAGE
public static final int PACKAGE
package (доступ по умолчанию), который может влиять на результат lookupModes. Значение — 0x08, которое не имеет значимого соответствия какому-либо конкретному биту-модификатору.- См. также:
MODULE
public static final int MODULE
module, который может влиять на результат lookupModes. Значение — 0x10, которое не имеет значимого соответствия какому-либо конкретному биту-модификатору. В сочетании с битом-модификатором PUBLIC объект Lookup с этим режимом поиска может обращаться ко всем открытым типам в модуле класса поиска и к открытым типам в пакетах, экспортируемых другими модулями в модуль класса поиска. Если этот режим поиска установлен, предыдущий класс поиска всегда равен null.
- Начиная с:
- 9
- См. также:
UNCONDITIONAL
public static final int UNCONDITIONAL
unconditional, который может влиять на результат lookupModes. Значение — 0x20, которое не имеет значимого соответствия какому-либо конкретному биту-модификатору. Объект Lookup с этим режимом поиска предполагает наличие доступности для чтения. Этот режим поиска позволяет обращаться ко всем открытым членам открытых типов всех модулей, если тип находится в пакете, который exported unconditionally. Если этот режим поиска установлен, предыдущий класс поиска всегда равен null.
- Начиная с:
- 9
- См. также:
ORIGINAL
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, если этот поиск был перенесён из прежнего класса поиска в одном модуле в новый класс поиска в другом модуле.
- Возвращает:
- класс поиска из другого модуля, из которого этот объект поиска был ранее перенесён, либо
null - Начиная с:
- 14
- См. также:
lookupModes
public int lookupModes()
Недавно созданный объект поиска для класса вызывающего кода имеет все возможные биты, кроме UNCONDITIONAL. У объекта поиска для нового класса поиска, созданного на основе предыдущего объекта поиска, некоторые биты режима могут быть сброшены. Биты режима также можно сбросить напрямую. После сброса биты режима нельзя восстановить из объекта поиска с ограниченными правами. Это позволяет ограничить доступ через новый объект поиска так, чтобы он мог получать доступ только к именам, доступным исходному объекту поиска, а также новому классу поиска.
- Возвращает:
- режимы поиска, ограничивающие типы доступа, выполняемого этим объектом поиска
- См. также:
in
public MethodHandles.Lookup in(Class<?> requestedLookupClass)
lookupClass. Однако гарантируется, что полученный объект Lookup не будет иметь больше возможностей доступа, чем исходный. В частности, возможности доступа могут быть утрачены следующим образом:
- Если новый класс поиска отличается от старого класса поиска, то есть утрачивается доступ
ORIGINAL. - Если новый класс поиска находится в модуле, отличном от модуля старого класса, то есть утрачивается доступ
MODULE. - Если новый класс поиска находится в пакете, отличном от пакета старого класса, защищённые и члены с доступом по умолчанию (пакетным доступом) будут недоступны, то есть утрачивается доступ
PROTECTEDиPACKAGE. - Если новый класс поиска не входит в тот же пакет, что и старый класс, приватные члены будут недоступны, а защищённые члены будут недоступны по наследованию, то есть утрачивается доступ
PRIVATE. (Защищённые члены могут оставаться доступными благодаря принадлежности к одному пакету.) - Если новый класс поиска недоступен этому объекту поиска, то никакие члены, даже публичные, не будут доступны; то есть утрачиваются все режимы доступа.
- Если новый класс поиска, старый класс поиска и предыдущий класс поиска находятся в разных модулях, то есть выполняется перенос в третий модуль, утрачиваются все режимы доступа.
Новый предыдущий класс поиска выбирается следующим образом:
- Если у нового объекта поиска установлен бит
UNCONDITIONAL, новый предыдущий класс поиска равенnull. - Если новый класс поиска находится в том же модуле, что и старый класс поиска, новым предыдущим классом поиска становится старый предыдущий класс поиска.
- Если новый класс поиска находится в модуле, отличном от модуля старого класса поиска, новым предыдущим классом поиска становится старый класс поиска.
Возможности полученного объекта поиска по загрузке классов (используемые при вызовах findClass(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) с именем класса из того же пакета, что и класс поиска.
Этот метод не запускает инициализатор класса. Инициализатор класса может быть запущен позднее, как описано в разделе 12.4 Спецификации языка Java.
- Параметры:
-
bytes— байты класса - Возвращает:
- объект
Classдля класса - Выбрасывает:
-
IllegalAccessException— если этот объект поиска не имеет доступаPACKAGE -
ClassFormatError— еслиbytesне является структуройClassFile -
IllegalArgumentException— еслиbytesобозначает класс из пакета, отличного от пакета класса поиска, или еслиbytesне является классом или интерфейсом (в значении элементаaccess_flagsустановлен флагACC_MODULE) -
VerifyError— если вновь созданный класс не прошёл проверку -
LinkageError— если вновь созданный класс не удалось связать по какой-либо другой причине -
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имеет тот же динамический пакет, модуль и домен защиты, что и класс поиска данногоLookup. - Пусть
GN— это двоичное имя, полученное заменой косых черт ASCII на точки ASCII вN(двоичном имени, записанном во внутренней форме). Для экземпляраClass, представляющегоC:-
Class.getName()возвращает строкуGN + "/" + <suffix>, хотя это не является допустимым двоичным именем класса или интерфейса. -
Class.descriptorString()возвращает строку"L" + N + "." + <suffix> + ";", хотя это не является допустимым именем дескриптора типа. -
Class.describeConstable()возвращает пустой объект optional, посколькуCнельзя описать в номинальной форме.
-
- Константе, указанной
После создания C виртуальная машина Java связывает его. Связывание выполняется согласно JVMS 5.4.3 со следующими изменениями:
- Во время проверки, если необходимо загрузить класс с именем
CN, попытка завершается успешно и возвращает классC. Запрос к какому-либо загрузчику классов не выполняется. - При любой попытке разрешить запись в пуле констант времени выполнения, указанную
this_class, считается, что символьная ссылка разрешена вC, и разрешение всегда немедленно завершается успешно.
Если параметр initialize имеет значение true, виртуальная машина Java инициализирует C.
Только что созданный класс или интерфейс C служит классом поиска объекта Lookup, возвращаемого этим методом. C является скрытым в том смысле, что ни один другой класс или интерфейс не может ссылаться на C через запись в пуле констант. То есть скрытый класс или интерфейс не может быть указан другим классом в качестве суперкласса, типа поля, типа параметра метода или типа возвращаемого значения метода. Это объясняется тем, что у скрытого класса или интерфейса нет двоичного имени, поэтому отсутствует внутренняя форма, которую можно было бы записать в пул констант какого-либо класса. Скрытый класс или интерфейс нельзя обнаружить с помощью Class.forName(String, boolean, ClassLoader), ClassLoader.loadClass(String, boolean) или findClass(String), а также нельзя изменить с помощью Java-агентов или инструментальных агентов, использующих интерфейс инструментирования виртуальной машины Java (JVM Tool Interface).
Класс или интерфейс, созданный загрузчиком классов, имеет с ним прочную связь. То есть каждый объект Class содержит ссылку на ClassLoader, который определил его. Это означает, что класс, созданный загрузчиком классов, может быть выгружен только в том случае, если его определяющий загрузчик недостижим и, следовательно, может быть освобождён сборщиком мусора (JLS 12.7). Однако по умолчанию скрытый класс или интерфейс может быть выгружен, даже если загрузчик классов, помеченный как его определяющий загрузчик, достижим. Такое поведение полезно, когда скрытый класс или интерфейс используется несколькими классами, определёнными произвольными загрузчиками классов. В других случаях скрытый класс или интерфейс может быть связан с одним классом (или небольшим числом классов) с тем же определяющим загрузчиком, что и у скрытого класса или интерфейса. В таких случаях, когда время жизни скрытого класса или интерфейса должно совпадать со временем жизни обычного класса или интерфейса, в options можно передать параметр STRONG. Это обеспечивает скрытому классу такую же прочную связь с загрузчиком классов, помеченным как его определяющий загрузчик, какую обычный класс или интерфейс имеет со своим определяющим загрузчиком. Если 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для скрытого класса с доступом original и с полными привилегиями - Вызывает исключение:
-
IllegalAccessException— если данныйLookupне имеет доступа с полными привилегиями -
ClassFormatError— еслиbytesне является структуройClassFile -
UnsupportedClassVersionError— еслиbytesимеет неподдерживаемую основную или дополнительную версию -
IllegalArgumentException— еслиbytesобозначает класс в пакете, отличном от пакета класса поиска, или еслиbytesне является классом или интерфейсом (в значении элементаaccess_flagsустановлен флагACC_MODULE) -
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), как если бы в скрытый класс было внедрено закрытое статическое final-поле без имени, инициализируемое заданным classData первой инструкцией инициализатора класса. Только что созданный класс связывается виртуальной машиной Java.
Методы MethodHandles::classData и MethodHandles::classDataAt можно использовать для получения classData.
- Примечание к API:
- Фреймворк может создать скрытый класс с данными класса, содержащими один или несколько объектов, а затем загрузить данные класса в виде динамически вычисляемых констант с помощью метода начальной загрузки. Метод
Class dataдоступен только объекту поиска, созданному только что определённым скрытым классом, но недоступен другим участникам того же гнезда (в отличие от закрытых статических полей, доступных участникам гнезда). Следует учитывать изменяемость данных, например при передаче через данные класса массива или другой изменяемой структуры. Изменение любого значения, хранящегося в данных класса во время выполнения, может привести к непредсказуемому поведению. Если данные класса представляют собойList, рекомендуется сделать их неизменяемыми, например с помощьюList::of. - Параметры:
-
bytes— байты класса -
classData— предварительно инициализированные данные класса -
initialize— еслиtrue, класс будет инициализирован. -
options— параметры класса - Возвращает:
- объект
Lookupдля скрытого класса с доступом original и с полными привилегиями - Вызывает исключение:
-
IllegalAccessException— если данныйLookupне имеет доступа с полными привилегиями -
ClassFormatError— еслиbytesне является структуройClassFile -
UnsupportedClassVersionError— еслиbytesимеет неподдерживаемую основную или дополнительную версию -
IllegalArgumentException— еслиbytesобозначает класс в пакете, отличном от пакета класса поиска, или еслиbytesне является классом или интерфейсом (в значении элементаaccess_flagsустановлен флагACC_MODULE) -
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, всегда имеют ограниченный доступ, поэтому в их представлении отображается суффикс. (Может показаться странным, что защищённый доступ имеет более высокий уровень, чем закрытый. Если рассматривать защищённый доступ отдельно от пакетного, он утрачивается первым, поскольку требует наличия непосредственного отношения подкласса между вызывающим и вызываемым объектами.)
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завершается неудачей -
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(VarHandle.AccessMode, 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завершается неудачей -
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завершается неудачей -
NullPointerException— если какой-либо аргумент равен null
findClass
public Class<?> findClass(String targetName) throws ClassNotFoundException, IllegalAccessException
Lookup, как если бы он был разрешён инструкцией ldc. Такое разрешение, описанное в JVMS 5.4.3.1, пытается найти и загрузить класс, а затем определяет, доступен ли класс этому объекту поиска. Для класса или интерфейса именем является двоичное имя. Для массива размерности n имя начинается с n вхождений '[', за которыми следует тип элемента, закодированный в таблице, указанной в Class.getName().
Контекст поиска здесь определяется классом поиска, его загрузчиком классов и режимами поиска.
- Параметры:
-
targetName— двоичное имя класса или строка, представляющая класс массива - Возвращает:
- запрошенный класс.
- Исключения:
-
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 инициализируется текущим потоком.
- Параметры типа:
T— тип инициализируемого класса- Параметры:
-
targetClass— инициализируемый класс - Возвращает:
-
targetClass, который был инициализирован или инициализируется текущим потоком. - Исключения:
-
IllegalArgumentException— еслиtargetClassимеет примитивный тип, являетсяvoidили массивом -
IllegalAccessException— еслиtargetClassнедоступен этому объекту поиска -
ExceptionInInitializerError— если инициализация класса, вызванная этим методом, завершается с ошибкой - См. Спецификацию виртуальной машины 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является открытым типом в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читает Module.canRead(Module)M0, а тип находится в пакете, экспортируемом как минимум дляM1. -
targetClassнаходится вM1, иM0читает Module.canRead(Module)M1, а тип находится в пакете, экспортируемом как минимум дляM0. -
targetClassнаходится в третьем модулеM2, и какM0, так иM1читаютM2, а тип находится в пакете, экспортируемом как минимум для обоих модулей:M0иM2.
В противном случае targetClass недоступен.
- Параметры типа:
T— тип класса, для которого проверяется доступ- Параметры:
-
targetClass— класс, для которого проверяется доступ - Возвращает:
-
targetClass, для которого выполнена проверка доступа - Исключения:
-
IllegalAccessException— если класс недоступен из класса поиска и предыдущего класса поиска, если он присутствует, в разрешённых режимах доступа. -
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завершается неудачно -
NullPointerException— если какой-либо аргумент равен null
findGetter
public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
- Параметры:
-
refc— класс или интерфейс, из которого вызывается метод -
name— имя поля -
type— тип поля - Возвращает:
- дескриптор метода, который может считывать значения из поля
- Исключения:
-
NoSuchFieldException— если поле не существует -
IllegalAccessException— если проверка доступа завершается неудачно или поле являетсяstatic -
NullPointerException— если какой-либо аргумент равен null - См. также:
findSetter
public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
- Параметры:
-
refc— класс или интерфейс, из которого вызывается метод -
name— имя поля -
type— тип поля - Возвращает:
- дескриптор метода, который может записывать значения в поле
- Исключения:
-
NoSuchFieldException— если поле не существует -
IllegalAccessException— если проверка доступа завершается неудачно или поле являетсяstaticилиfinal -
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(Object)иDouble.equals(Object), в частности при сравнении значений NaN или сравнении-0.0с+0.0. При выполнении операций compare-and-set или compare-and-exchange с такими значениями следует соблюдать осторожность, поскольку операция может неожиданно завершиться неудачно. В Java существует множество возможных значений NaN, которые считаютсяNaN, хотя ни одна предоставляемая Java операция с плавающей точкой IEEE 754 не может различить их. Операция может завершиться неудачно, если ожидаемое значение или значение-свидетель является 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 -
NullPointerException— если какой-либо аргумент равен null - Начиная с версии:
- 9
findStaticGetter
public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
При вызове возвращённого дескриптора метода класс поля будет инициализирован, если он ещё не был инициализирован.
- Параметры:
-
refc— класс или интерфейс, из которого вызывается метод -
name— имя поля -
type— тип поля - Возвращает:
- дескриптор метода, который может считывать значения из поля
- Исключения:
-
NoSuchFieldException— если поле не существует -
IllegalAccessException— если проверка доступа завершается неудачно или поле не являетсяstatic -
NullPointerException— если какой-либо аргумент равен null
findStaticSetter
public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
При вызове возвращённого дескриптора метода класс поля будет инициализирован, если он ещё не был инициализирован.
- Параметры:
-
refc— класс или интерфейс, из которого вызывается метод -
name— имя поля -
type— тип поля - Возвращает:
- дескриптор метода, который может записывать значения в поле
- Исключения:
-
NoSuchFieldException— если поле не существует -
IllegalAccessException— если проверка доступа завершается неудачно, поле не являетсяstaticили являетсяfinal -
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(Object)иDouble.equals(Object), в частности при сравнении значений NaN или сравнении-0.0с+0.0. При выполнении операций compare-and-set или compare-and-exchange с такими значениями следует соблюдать осторожность, поскольку операция может неожиданно завершиться неудачно. В Java существует множество возможных значений NaN, которые считаютсяNaN, хотя ни одна предоставляемая Java операция с плавающей точкой IEEE 754 не может различить их. Операция может завершиться неудачно, если ожидаемое значение или значение-свидетель является NaN и преобразуется (возможно, платформозависимым способом) в другое значение NaN, вследствие чего его побитовое представление меняется (подробности см. вFloat.intBitsToFloat(int)илиDouble.longBitsToDouble(long)). Значения-0.0и+0.0имеют разные побитовые представления, но считаются равными при использовании примитивного оператора==. Операция может завершиться неудачно, если, например, числовой алгоритм вычислил ожидаемое значение, скажем,-0.0, а ранее вычислил значение-свидетель, скажем,+0.0. - Параметры:
-
decl— класс, объявляющий статическое поле -
name— имя поля -
type— тип поля, типаT - Возвращает:
- VarHandle, предоставляющий доступ к статическому полю
- Исключения:
-
NoSuchFieldException— если поле не существует -
IllegalAccessException— если проверка доступа завершается неудачно или поле не являетсяstatic -
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завершается неудачно -
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, дескриптор метода не будет принимать аргументов. В противном случае его единственным аргументом будет экземпляр, содержащий поле. Если флаг accessible объекта Field не установлен, проверка доступа немедленно выполняется от имени класса поиска. Если поле является статическим и возвращенный дескриптор метода вызывается, класс поля будет инициализирован, если он еще не был инициализирован.
- Параметры:
-
f— отраженное поле - Возвращает:
- дескриптор метода, который может загружать значения из отраженного поля
- Вызывает исключения:
-
IllegalAccessException— если проверка доступа завершается неудачей -
NullPointerException— если аргумент равен null
unreflectSetter
public MethodHandle unreflectSetter(Field f) throws IllegalAccessException
static, дескриптор метода будет принимать один аргумент типа значения поля — значение, которое нужно сохранить. В противном случае двумя аргументами будут экземпляр, содержащий поле, и значение, которое нужно сохранить. Если флаг accessible объекта Field не установлен, проверка доступа немедленно выполняется от имени класса поиска. Если поле является final, доступ для записи будет запрещен и проверка доступа завершится неудачей, за исключением определенных узких обстоятельств, описанных для Field.set. Дескриптор метода возвращается только в том случае, если соответствующий вызов метода set объекта Field мог бы завершиться нормально. В частности, поля, которые одновременно являются 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(Object)иDouble.equals(Object), в частности при сравнении значений NaN или сравнении-0.0с+0.0. При выполнении операций compare-and-set или compare-and-exchange с такими значениями следует проявлять осторожность, поскольку операция может неожиданно завершиться неудачей. В Java существует множество значений NaN, которые считаютсяNaN, хотя ни одна операция с плавающей точкой 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— прямой дескриптор метода для разложения на компоненты символьной ссылки - Возвращает:
- символьную ссылку, которую можно использовать для восстановления этого дескриптора метода с помощью данного объекта поиска
- Вызывает исключения:
-
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 должен иметь полный привилегированный доступ, чтобы получать доступ ко всем членам, доступным классу поиска.- Возвращает:
-
true, если этот объект поиска имеет полный привилегированный доступ. - С версии:
- 14
- См. также:
© 1993, 2025, 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/25/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html
PRIVATE, подразумевающего полный привилегированный доступ, однако с тех пор доступMODULEстал независимым от доступаPRIVATE.