Класс 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, lookup все равно может иметь успех, даже если нет эквивалентного выражения Java или константы байткода. - Аналогично, если
TилиMTне доступен символично из загрузчика класса lookup, lookup все равно может иметь успех. Например, lookup дляMethodHandle.invokeExactиMethodHandle.invokeвсегда будут успешными, независимо от запрошенного типа. - Если искомый метод имеет очень большую арность, создание обработчика метода может завершиться неудачей с исключением
IllegalArgumentExceptionиз-за того, что тип обработчика метода имеет слишком много параметров.
Проверка доступа
Проверки доступа применяются в методах фабрикиLookup при создании обработчика метода. Это ключевое различие от API ядра рефлексии, так как java.lang.reflect.Method.invoke выполняет проверку доступа для каждого вызывающего объекта при каждом вызове. Все проверки доступа начинаются с объекта Lookup, который сравнивает свой записанный класс lookup со всеми запросами на создание обработчиков методов. Один объект Lookup может использоваться для создания любого количества обработчиков методов с проверкой доступа, все они проверяются относительно одного класса lookup.
Объект Lookup может быть использован другим доверенным кодом, например, протоколом метаобъектов. Общий объект Lookup делегирует возможность создавать обработчики методов для приватных членов класса lookup. Даже если привилегированный код использует объект Lookup, проверка доступа ограничена привилегиями исходного класса lookup.
Lookup может завершиться неудачей, потому что содержащий класс недоступен для класса lookup, или потому что необходимый член класса отсутствует, или потому что необходимый член класса недоступен для класса lookup, или потому что объект lookup недостаточно доверен, чтобы получить доступ к члену. В случае функции установщика поля для поля final, принуждение к финальности рассматривается как своего рода контроль доступа, и lookup завершится неудачей, за исключением особых случаев Lookup.unreflectSetter. В любом из этих случаев будет брошено исключение ReflectiveOperationException из попытки lookup. Точный класс будет одним из следующих:
- NoSuchMethodException — если запрашивается метод, но он не существует
- NoSuchFieldException — если запрашивается поле, но оно не существует
- IllegalAccessException — если член существует, но проверка доступа завершается неудачей
В целом, условия, при которых обработчик метода может быть найден для метода M, не более строги, чем условия, при которых класс lookup мог бы скомпилировать, проверить и разрешить вызов M. Там, где JVM генерировала бы исключения, такие как NoSuchMethodError, lookup обработчика метода обычно генерирует соответствующее проверяемое исключение, например, NoSuchMethodException. И эффект вызова обработчика метода, полученного в результате lookup, точно эквивалентен выполнению скомпилированного, проверенного и разрешенного вызова M. То же самое относится к полям и конструкторам.
Обсуждение: Проверки доступа применяются только к именованным и отраженным методам, конструкторам и полям. Другие методы создания обработчиков методов, такие как MethodHandle.asType, не требуют проверок доступа и используются независимо от любого объекта Lookup.
Если требуемый член — protected, применяются обычные правила JVM, включая требование, что класс поиска должен находиться в том же пакете, что и требуемый член, или унаследовать этот член. (См. спецификацию Java Virtual Machine, разделы 4.9.2, 5.4.3.5 и 6.4.) Кроме того, если требуемый член — это нестатическое поле или метод в другом пакете, полученная обработка методов может быть применена только к объектам класса поиска или одному из его подклассов. Это требование обеспечивается сужением типа ведущего this параметра от C (который обязательно является суперклассом класса поиска) до самого класса поиска.
JVM накладывает аналогичное требование на invokespecial инструкцию, то есть аргумент получателя должен соответствовать как разрешённому методу, так и текущему классу. Опять же, это требование обеспечивается сужением типа ведущего параметра до полученной обработки методов. (См. спецификацию Java Virtual Machine, раздел 4.10.1.9.)
JVM представляет конструкторы и блоки статической инициализации как внутренние методы со специальными именами ("<init>" и "<clinit>"). Внутренний синтаксис инструкций вызова позволяет им ссылаться на такие внутренние методы, как на обычные методы, но верификатор байткода JVM отклоняет их. Поиск такого внутреннего метода даст NoSuchMethodException.
Если отношения между вложенными типами выражены напрямую через NestHost и NestMembers атрибуты (см. спецификацию Java Virtual Machine, разделы 4.7.28 и 4.7.29), то связанный Lookup объект предоставляет прямой доступ к классу поиска и всем его вложенным классам (см. Class.getNestHost). В противном случае доступ между вложенными классами обеспечивается Java-компилятором, создающим оберточный метод для доступа к закрытому методу другого класса в том же вложении. Например, вложенный класс C.D может получить доступ к закрытым членам других связанных классов, таким как C, C.D.E или C.B, но Java-компилятор может потребоваться сгенерировать оберточные методы в этих связанных классах. В таких случаях объект Lookup на C.E не смог бы получить доступ к этим закрытым членам. Рабочий обход этого ограничения — метод Lookup.in, который может преобразовать поиск в C.E в поиск на любом из этих других классов без специального повышения привилегий.
Доступ к данному объекту поиска может быть ограничен, в соответствии с его набором lookupModes, до подмножества членов, обычно доступных классу поиска. Например, метод publicLookup производит объект поиска, которому разрешено получить доступ только к общедоступным членам общедоступных классов экспортируемых пакетов. Чувствительный к вызывающей стороне метод lookup производит объект поиска с полными возможностями относительно класса вызывающей стороны, для эмуляции всех поддерживаемых поведенческих особенностей байткода. Также метод Lookup.in может произвести объект поиска с меньшим количеством режимов доступа, чем исходный объект поиска.
Обсуждение доступа к закрытым и модулям: Мы говорим, что поиск имеет закрытый доступ, если его режимы поиска включают возможность доступа к private членам (что включает закрытые члены вложенных классов). Как задокументировано в соответствующих методах в других местах, только поиски с закрытым доступом обладают следующими возможностями:
- доступ к закрытым полям, методам и конструкторам класса поиска и его вложенных классов
- создание обработок методов, которые
emulate invokespecialинструкции - создание
delegated lookup objects, которые имеют закрытый доступ к другим классам в рамках того же элемента пакета
Аналогично, поиск с доступом к модулю гарантирует, что исходный создатель поиска был членом в том же модуле, что и класс поиска.
Закрытый и модульный доступ — это независимые режимы; поиск может иметь тот или другой, оба или ни одного. Поиск, обладающий обоими режимами доступа, обладает полным доступом с привилегиями.
Поиск с исходным доступом гарантирует, что этот поиск создан исходным классом поиска и вызываемым VM методом загрузки. Такой поиск с исходным доступом также имеет закрытый и модульный доступ, который обладает следующими дополнительными возможностями:
- создание обработок методов, которые вызывают методы, чувствительные к вызывающей стороне, такие как
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, созданного любым из следующих фабричных или преобразовательных методов: | Объект поиска | Оригинальный | Защищенный | Приватный | Пакет | Модуль | Публичный |
|---|---|---|---|---|---|---|
CL = MethodHandles.lookup() в C
| ORI | PRO | PRI | PAC | MOD | 1R |
CL.in(C1) в том же пакете | PAC | MOD | 1R | |||
CL.in(C1) в том же модуле | MOD | 1R | ||||
CL.in(D) в другом модуле | 2R | |||||
CL.in(D).in(C) возврат в модуль | 2R | |||||
PRI1 = privateLookupIn(C1,CL) | PRO | PRI | PAC | MOD | 1R | |
PRI1a = privateLookupIn(C,PRI1) | PRO | PRI | PAC | MOD | 1R | |
PRI1.in(C1) в том же пакете | PAC | MOD | 1R | |||
PRI1.in(C1) в другом пакете | MOD | 1R | ||||
PRI1.in(D) в другом модуле | 2R | |||||
PRI1.dropLookupMode(PROTECTED) | PRI | PAC | MOD | 1R | ||
PRI1.dropLookupMode(PRIVATE) | PAC | MOD | 1R | |||
PRI1.dropLookupMode(PACKAGE) | MOD | 1R | ||||
PRI1.dropLookupMode(MODULE) | 1R | |||||
PRI1.dropLookupMode(PUBLIC) | нет | |||||
PRI2 = privateLookupIn(D,CL) | PRO | PRI | PAC | 2R | ||
privateLookupIn(D,PRI1) | PRO | PRI | PAC | 2R | ||
privateLookupIn(C,PRI2) неудачно | IAE | |||||
PRI2.in(D2) в том же пакете | PAC | 2R | ||||
PRI2.in(D2) в другом пакете | 2R | |||||
PRI2.in(C1) возврат в модуль | 2R | |||||
PRI2.in(E) переход в третий модуль | нет | |||||
PRI2.dropLookupMode(PROTECTED) | PRI | PAC | 2R | |||
PRI2.dropLookupMode(PRIVATE) | PAC | 2R | ||||
PRI2.dropLookupMode(PACKAGE) | 2R | |||||
PRI2.dropLookupMode(MODULE) | 2R | |||||
PRI2.dropLookupMode(PUBLIC) | нет | |||||
CL.dropLookupMode(PROTECTED) | PRI | PAC | MOD | 1R | ||
CL.dropLookupMode(PRIVATE) | PAC | MOD | 1R | |||
CL.dropLookupMode(PACKAGE) | MOD | 1R | ||||
CL.dropLookupMode(MODULE) | 1R | |||||
CL.dropLookupMode(PUBLIC) | нет | |||||
PUB = publicLookup() | У | |||||
PUB.in(D) в другом модуле | У | |||||
PUB.in(D).in(E) третий модуль | У | |||||
PUB.dropLookupMode(UNCONDITIONAL) | нет | |||||
privateLookupIn(C1,PUB) неудачно | IAE | |||||
ANY.in(X), для недоступного X
| нет |
Примечания:
- Классы
CиC1находятся в модулеM1, ноDиD2находятся в модулеM2, аEнаходится в модулеM3.Xобозначает класс, недоступный для поиска.ANYобозначает любой из примеров поисков. -
ORIуказывает, что установлен битORIGINAL,PROуказывает, что установлен битPROTECTED,PRIуказывает, что установлен битPRIVATE,PACуказывает, что установлен битPACKAGE,MODуказывает, что установлен битMODULE,1Rи2Rуказывают, что установлен битPUBLIC,Uуказывает, что установлен битUNCONDITIONAL,IAEуказывает, что выброшено исключениеIllegalAccessException. - Доступ к общедоступности бывает трех видов:
- безусловный (
U): поиск предполагает читаемость. Поиск имеетnullпредыдущий класс поиска. - чтение в одном модуле (
1R): проверка доступа по модулям выполняется относительно класса поиска. Поиск имеетnullпредыдущий класс поиска. - чтение в двух модулях (
2R): проверка доступа по модулям выполняется относительно класса поиска и предыдущего класса поиска. Поиск имеет непустой предыдущий класс поиска, который находится в другом модуле по сравнению с текущим классом поиска.
- безусловный (
- Любая попытка обратиться к третьему модулю теряет весь доступ.
- Если целевой класс
Xнедоступен дляLookup::in, все режимы доступа отключаются.
Методы, чувствительные к вызывающей стороне
Небольшое количество методов Java обладает специальным свойством, называемым чувствительностью к вызывающей стороне. Метод, чувствительный к вызывающей стороне, может вести себя по-разному в зависимости от идентичности его непосредственного вызывающего метода.Если запрашивается обработчик метода для метода, чувствительного к вызывающей стороне, применяются общие правила для поведения байткода, но они учитывают класс поиска особым образом. Результирующий обработчик метода ведет себя так, как будто он был вызван инструкцией, содержащейся в классе поиска, чтобы метод, чувствительный к вызывающей стороне, обнаружил класс поиска. (В отличие от этого, вызывающий обработчик метода игнорируется.) Таким образом, в случае методов, чувствительных к вызывающей стороне, разные классы поиска могут привести к поведению обработчиков методов.
В случаях, когда объект поиска publicLookup(), или какой-либо другой объект поиска без оригинального доступа, класс поиска игнорируется. В таких случаях не может быть создан обработчик метода, чувствительный к вызывающей стороне, доступ запрещен, и поиск завершается с ошибкой IllegalAccessException.
Обсуждение: Например, чувствительный к вызывающей стороне метод Class.forName(x) может возвращать различные классы или выбрасывать различные исключения, в зависимости от загрузчика классов вызывающего его класса. Публичный поиск Class.forName потерпит неудачу, так как нет разумного способа определить его поведение байткода.
Если приложение кэширует обработчики методов для широкого совместного использования, оно должно использовать publicLookup() для их создания. Если будет произведен поиск Class.forName, он потерпит неудачу, и приложение должно предпринять соответствующие действия в этом случае. Возможно, что последующий поиск, возможно, во время вызова метода загрузки, сможет включить конкретную идентичность вызывающей стороны, сделав метод доступным.
Функция MethodHandles.lookup чувствительна к вызывающей стороне, чтобы обеспечить надёжную основу для поиска. Почти все другие методы API JSR 292 полагаются на объекты поиска для проверки запросов доступа.
- С:
- 1.7
Краткое описание вложенных классов
| Modifier and Type | Class | Описание |
|---|---|---|
static enum |
MethodHandles.Lookup.ClassOption |
Набор параметров класса, которые указывают, добавляется ли динамически созданный метод Lookup::defineHiddenClass как новый член вложенного класса класса поиска и/или имеет ли скрытый класс тесную связь с загрузчиком классов, помеченным как его определяющий загрузчик. |
Краткое описание полей
| Modifier and Type | Field | Описание |
|---|---|---|
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 | Описание |
|---|---|---|
<T> Class |
accessClass |
Определяет, доступен ли класс из контекста поиска, определенного этим объектом Lookup. |
MethodHandle |
bind |
Создает обработчик метода со связыванием во время выполнения для нестатического метода. |
Class |
defineClass |
Создает и связывает класс или интерфейс из bytes с тем же загрузчиком классов и в том же пакете времени выполнения и областью защиты, что и класс поиска lookup class, как при вызове 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 модификатора. Объект с таким режимом поиска выполняет проверку доступа между модулями относительно класса поиска и предыдущего класса поиска, если таковые имеются.
- См. также:
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 модификатором, объект с таким режимом поиска может получить доступ ко всем публичным типам в модуле класса поиска и публичным типам в пакетах, экспортированных другими модулями в модуль класса поиска. Если этот режим поиска установлен, предыдущий класс поиска всегда null.
- С:
- 9
- См. также:
БЕЗУСЛОВНЫЙ
public static final int UNCONDITIONAL
unconditional, который может повлиять на результат lookupModes. Значение равно 0x20, которое не имеет прямого соответствия с каким-либо битом модификатора. Объект поиска с этим режимом предполагает чтение. Этот режим поиска может получить доступ ко всем публичным членам публичных типов всех модулей, когда тип находится в пакете, который exported unconditionally. Если этот режим поиска установлен, предыдущий класс поиска всегда null.
- С:
- 9
- См. также:
ИСТОЧНИК
public static final int ORIGINAL
original, который может повлиять на результат lookupModes. Значение равно 0x40, которое не имеет прямого соответствия с каким-либо битом модификатора. Если этот режим поиска установлен, объект Lookup должен быть создан исходным классом поиска, вызвав метод MethodHandles.lookup(), или с помощью метода загрузки, вызванного виртуальной машиной. Объект Lookup с этим режимом поиска имеет полный доступ.
- С:
- 16
- См. также:
Подробное описание методов
lookupClass
public Class<?> lookupClass()
Если у этого объекта поиска есть предыдущий класс поиска, проверки доступа выполняются как против класса поиска, так и против предыдущего класса поиска.
Класс подразумевает максимальный уровень разрешений доступа, но разрешения могут быть дополнительно ограничены битовой маской lookupModes, которая управляет возможностью доступа к непубличным членам.
- Возвращает:
- класс поиска, от имени которого этот объект поиска находит члены
- См. также:
previousLookupClass
public Class<?> previousLookupClass()
null. Объект поиска, созданный методами-фабриками, такими как lookup() и publicLookup(), имеет 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(java.lang.String)) определяются загрузчиком класса поиска, который может измениться в результате этой операции.
- Parameters:
-
requestedLookupClass- желаемый класс поиска для нового объекта поиска - Returns:
- объект поиска, который указывает на желаемый класс поиска, или тот же объект, если изменений нет
- Throws:
-
IllegalArgumentException- еслиrequestedLookupClassявляется примитивным типом, void или классом массива -
NullPointerException- если аргумент равен null - See Also:
dropLookupMode
public MethodHandles.Lookup dropLookupMode(int modeToDrop)
PUBLIC, MODULE, PACKAGE, PROTECTED, PRIVATE, ORIGINAL или UNCONDITIONAL. Если этот поиск является публичным поиском, этот поиск имеет установленный режим UNCONDITIONAL и не имеет других режимов. При удалении UNCONDITIONAL из публичного поиска, результирующий поиск не имеет доступа.
Если этот поиск не является публичным, то применяется следующее, независимо от его режимов поиска. PROTECTED и ORIGINAL всегда удаляются, поэтому результирующий режим поиска никогда не будет иметь этих возможностей доступа. При удалении PACKAGE, результирующий поиск не будет иметь PACKAGE или PRIVATE доступа. При удалении MODULE, результирующий поиск не будет иметь MODULE, PACKAGE или PRIVATE доступа. При удалении PUBLIC, результирующий поиск не имеет доступа.
- API Note:
- Поиск с режимом
PACKAGE, но без режимаPRIVATE, может безопасно делегировать доступ к непубличным членам в пакете класса поиска, не предоставляя приватный доступ. Поиск с режимомMODULE, но без режимаPACKAGE, может безопасно делегироватьPUBLICдоступ в модуле класса поиска, не предоставляя доступ к пакету. Поиск с предыдущим классом поиска (и режимомPUBLIC, но без режимаMODULE) может безопасно делегировать доступ к публичным классам, доступным как для модуля класса поиска, так и для модуля предыдущего класса поиска. - Parameters:
-
modeToDrop- режим поиска для удаления - Returns:
- объект поиска, у которого отсутствует указанный режим, или тот же объект, если изменений нет
- Throws:
-
IllegalArgumentException- еслиmodeToDropне является одним изPUBLIC,MODULE,PACKAGE,PROTECTED,PRIVATE,ORIGINALилиUNCONDITIONAL - Since:
- 9
- See Also:
defineClass
public Class<?> defineClass(byte[] bytes) throws IllegalAccessException
bytes с тем же загрузчиком класса и в том же пакете выполнения и областью защиты, что и класс поиска этого поиска, как если бы был вызов ClassLoader::defineClass. Режимы поиска для данного поиска должны включать доступ PACKAGE, поскольку по умолчанию доступны пакетные члены класса. Режим поиска PACKAGE служит для аутентификации того, что объект поиска был создан вызывающим объектом в пакете выполнения (или получен от объекта поиска, который был первоначально создан кодом с соответствующими привилегиями для целевого класса в пакете выполнения).
Параметр bytes — байты класса действительного файла класса (как определено в спецификации The Java Virtual Machine Specification) с именем класса в том же пакете, что и класс поиска.
Этот метод не запускает инициализатор класса. Инициализатор класса может быть запущен в более позднее время, как описано в разделе 12.4 спецификации The Java Language Specification.
- Parameters:
-
bytes- байты класса - Returns:
- объект
Classдля класса - Throws:
-
IllegalAccessException- если у этого поиска нет доступаPACKAGE -
ClassFormatError- еслиbytesне является структуройClassFile -
IllegalArgumentException- еслиbytesобозначает класс в другом пакете, чем класс поиска, илиbytesне является классом или интерфейсом (ACC_MODULEфлаг установлен в значении элементаaccess_flags) -
VerifyError- если созданный класс не может быть проверен -
LinkageError- если созданный класс не может быть связан по любой другой причине -
NullPointerException- еслиbytesравенnull - Since:
- 9
- See Also:
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 modes) для данного
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— бинарное имя, полученное путём взятия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.
Класс или интерфейс, созданный загрузчиком классов, имеет тесную связь с этим загрузчиком. То есть, каждый объект 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- если класс будет инициализирован. -
options- параметры класса - Возвращает:
- объект
Lookupскрытого класса с исходным и полным доступом - Исключение:
-
IllegalAccessException- если у этогоLookupнет полного доступа -
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:
- Фреймворк может создать скрытый класс с данными класса с одним или несколькими объектами и загрузить данные класса как динамически вычисленные константы через метод загрузки.
Class dataдоступен только объекту поиска, созданному новым скрытым классом, но недоступен другим членам в том же вложенном (в отличие от приватных статических полей, которые доступны сородичам по вложению). Следует проявлять осторожность в отношении изменяемости, например, при передаче массива или другой изменяемой структуры через данные класса. Изменение любого значения, хранящегося в данных класса во время выполнения, может привести к непредсказуемому поведению. Если данные класса являютсяList, рекомендуется сделать их неизменяемыми, например, черезList::of. - Параметры:
-
bytes- байты класса -
classData- предварительно инициализированные данные класса -
initialize- еслиtrueкласс будет инициализирован. -
options- параметры класса - Возвращает:
- объект
Lookupскрытого класса с исходным и полным доступом - Исключение:
-
IllegalAccessException- если у этогоLookupнет полного доступа -
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, всегда имеют ограниченный доступ и отображают суффикс. (Может показаться странным, что защищенный доступ сильнее, чем частный. Если рассматривать его независимо от пакетного доступа, то защищенный доступ — первый, который теряется, так как он требует прямого наследования между вызывающим и вызываемым объектами.)
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(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завершился неудачно -
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 инициализируется текущей нитью.
- Type Parameters:
T- тип класса, подлежащего инициализации- Parameters:
-
targetClass- класс, подлежащий инициализации - Returns:
-
targetClass, который был инициализирован или инициализируется текущей нитью. - Throws:
-
IllegalArgumentException- еслиtargetClassявляется примитивным типом или классомvoidили массивом -
IllegalAccessException- еслиtargetClassнедоступен для данного поиска -
ExceptionInInitializerError- если инициализация класса, вызванная этим методом, завершилась неудачно - See Java Virtual Machine Specification:
- 5.5 Инициализация
- Since:
- 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читаетM0, а тип находится в пакете, экспортированном по крайней мере дляM1. -
targetClassнаходится вM1иM0читаетM1, а тип находится в пакете, экспортированном по крайней мере дляM0. -
targetClassнаходится в третьем модулеM2и обаM0иM1читаютM2, а тип находится в пакете, экспортированном по крайней мере дляM0иM2.
В противном случае targetClass недоступен.
- Type Parameters:
T- тип класса, для которого проверяется доступ- Parameters:
-
targetClass- класс, для которого проверяется доступ - Returns:
-
targetClass, для которого проверена доступность - Throws:
-
IllegalAccessException- если класс недоступен из класса поиска и предыдущего класса поиска (если он присутствует) с использованием разрешенных режимов доступа. -
NullPointerException- еслиtargetClassявляетсяnull - Since:
- 9
- See Also:
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завершается неудачей -
NullPointerException- если какой-либо аргумент равен null
findGetter
public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
- Parameters:
-
refc- класс или интерфейс, из которого осуществляется доступ к методу -
name- имя поля -
type- тип поля - Returns:
- обработчик метода, который может загружать значения из поля
- Throws:
-
NoSuchFieldException- если поле не существует -
IllegalAccessException- если проверка доступа завершилась неудачно, или если поле являетсяstatic -
NullPointerException- если какой-либо аргумент равен null - See Also:
findSetter
public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
- Parameters:
-
refc- класс или интерфейс, из которого осуществляется доступ к методу -
name- имя поля -
type- тип поля - Returns:
- обработчик метода, который может сохранять значения в поле
- Throws:
-
NoSuchFieldException- если поле не существует -
IllegalAccessException- если проверка доступа завершилась неудачно, или если поле являетсяstaticилиfinal -
NullPointerException- если какой-либо аргумент равен null - See Also:
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 -
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(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 -
NullPointerException- если любой аргумент равен null - С:
- 9
связывать
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 - См. также:
отразить
public MethodHandle unreflect(Method m) throws IllegalAccessException
accessible метода не установлен, проверка доступа выполняется немедленно от имени класса поиска. Если m не является публичным, не передавайте полученный обработчик недоверенным сторонам. Возвращаемый обработчик метода будет иметь переменную арность тогда и только тогда, когда установлен бит модификатора переменной арности метода (0x0080).
Если m статический и возвращаемый обработчик метода вызывается, класс метода будет инициализирован, если он ещё не был инициализирован.
- Параметры:
-
m— отражённый метод - Возвращает:
- обработчик метода, который может вызвать отражённый метод
- Исключение:
-
IllegalAccessException— если проверка доступа завершилась неудачно или если бит модификатора переменной арности метода установлен, иasVarargsCollectorзавершилась неудачно -
NullPointerException— если аргумент равен null
отразить специальный
public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException
invokespecial внутри явно указанного specialCaller. Тип обработчика метода будет таким же, как у метода, с предварительно добавленным типом получателя, ограниченным соответствующим образом. (Тип получателя будет specialCaller или подтипом.) Если флаг accessible метода не установлен, проверка доступа выполняется немедленно от имени класса поиска, как если бы инструкция invokespecial была связана. Перед разрешением метода, если явно указанный класс вызывающего не идентичен классу поиска, или если у этого объекта поиска нет привилегий частного доступа, доступ отклоняется.
Возвращаемый обработчик метода будет иметь переменную арность тогда и только тогда, когда бит модификатора переменной арности метода (0x0080) установлен.
- Параметры:
-
m— отражённый метод -
specialCaller— класс, номинально вызывающий метод - Возвращает:
- обработчик метода, который может вызвать отражённый метод
- Исключение:
-
IllegalAccessException— если проверка доступа завершилась неудачно, или если метод являетсяstatic, или если бит модификатора переменной арности метода установлен, иasVarargsCollectorзавершилась неудачно -
NullPointerException— если любой аргумент равен null
отразить конструктор
public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException
newInstance, создавая новый экземпляр класса конструктора по аргументам, переданным обработчику метода. Если флаг accessible конструктора не установлен, проверка доступа выполняется немедленно от имени класса поиска.
Возвращаемый обработчик метода будет иметь переменную арность тогда и только тогда, когда бит модификатора переменной арности конструктора (0x0080) установлен.
Если возвращаемый обработчик метода вызывается, класс конструктора будет инициализирован, если он ещё не был инициализирован.
- Параметры:
-
c— отражённый конструктор - Возвращает:
- обработчик метода, который может вызвать отражённый конструктор
- Исключение:
-
IllegalAccessException— если проверка доступа завершилась неудачно или если бит модификатора переменной арности метода установлен, иasVarargsCollectorзавершилась неудачно -
NullPointerException— если аргумент равен null
отразить геттер
public MethodHandle unreflectGetter(Field f) throws IllegalAccessException
static, обработчик метода не будет принимать аргументы. В противном случае его единственным аргументом будет экземпляр, содержащий поле. Если флаг Field объекта accessible не установлен, проверка доступа выполняется немедленно от имени класса поиска. Если поле является статическим, и если возвращаемый обработчик метода вызывается, класс поля будет инициализирован, если он ещё не был инициализирован.
- Параметры:
-
f— отражённое поле - Возвращает:
- обработчик метода, который может загружать значения из отражённого поля
- Исключение:
-
IllegalAccessException— если проверка доступа завершилась неудачно -
NullPointerException— если аргумент равен null
отразить сеттер
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- прямое обращение к методу, которое нужно раскрыть до символьных компонентов ссылки - Возвращает:
- символьная ссылка, которая может быть использована для реконструкции этого обработчика метода из этого объекта поиска
- Исключения:
-
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, 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://download.java.net/java/early_access/jdk24/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html
PRIVATE, который подразумевает полный доступ с правами, но доступMODULEс тех пор стал независимым от доступаPRIVATE.