Класс MethodHandles.Lookup
- Окружающий класс:
- MethodHandles
public static final class MethodHandles.Lookup extends Object
Класс поиска, которому нужно создать обработчики методов, вызовет MethodHandles.lookup, чтобы создать фабрику для себя. Когда объект фабрики Lookup создается, идентичность класса поиска определяется и безопасно сохраняется в объекте Lookup. Затем класс поиска (или его делегаты) могут использовать методы фабрики объекта Lookup для создания обработчиков методов для членов с проверкой доступа. Это включает все методы, конструкторы и поля, разрешенные классу поиска, даже приватные.
Методы фабрики Lookup
Методы фабрики объектаLookup соответствуют всем основным случаям использования методов, конструкторов и полей. Каждый обработчик методов, созданный методом фабрики, является функциональным эквивалентом определенного поведения байткода. (Поведения байткода описаны в разделе 5.4.3.5 спецификации Java Virtual Machine.) Вот краткое описание соответствия между этими методами фабрики и поведением полученных обработчиков методов: | выражение поиска | член | поведение байткода |
|---|---|---|
lookup.findGetter(C.class,"f",FT.class) | FT f; |
(T) this.f; |
lookup.findStaticGetter(C.class,"f",FT.class) |
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 ядра рефлексии имя thisOrNull обозначает нулевую ссылку, если доступный метод или поле статическое, и this в противном случае. Имена aMethod, aField, и aConstructor обозначают рефлективные объекты, соответствующие заданным членам, объявленным в типе C. Поведение байткода для операции findClass — это загрузка константного класса, как если бы это делалось с помощью ldc CONSTANT_Class. Это поведение представляется не как обработчик методов, а непосредственно как константа Class .
В случаях, когда данный член имеет переменную арность (т.е. метод или конструктор), возвращаемый обработчик методов также будет иметь переменную арность. Во всех других случаях возвращаемый обработчик методов будет иметь фиксированную арность.
Обсуждение: Эквивалентность между обработчиками методов поиска и базовыми членами класса и поведениями байткода может нарушаться несколькими способами:
- Если
Cнедоступен для загрузчика класса поиска символически, поиск всё же может пройти успешно, даже когда нет эквивалентного выражения Java или байткодовой константы. - Аналогично, если
TилиMTнедоступен для загрузчика класса поиска символически, поиск всё же может пройти успешно. Например, поиски дляMethodHandle.invokeExactиMethodHandle.invokeвсегда пройдут успешно, независимо от запрошенного типа. - Если установлен менеджер безопасности, он может запретить поиск по различным причинам (см. ниже). В отличие от этого, инструкция
ldcдля константыCONSTANT_MethodHandleне подлежит проверкам менеджера безопасности. - Если искомый метод имеет очень большую арность, создание обработчика методов может завершиться ошибкой
IllegalArgumentException, из-за того, что тип обработчика методов имеет слишком много параметров.
Проверка доступа
Проверки доступа применяются в методах фабрикиLookup, когда создаётся обработчик методов. Это ключевое отличие от API ядра рефлексии, поскольку java.lang.reflect.Method.invoke выполняет проверку доступа для каждого вызывающего по каждому вызову. Все проверки доступа начинаются с объекта Lookup, который сравнивает записанный класс поиска с каждым запросом на создание обработчиков методов. Один объект Lookup может быть использован для создания любого количества обработчиков методов с проверкой доступа, все проверяются по одному классу поиска.
Объект Lookup может быть общим для другого доверенного кода, например, метаобъектного протокола. Общий объект Lookup делегирует возможность создания обработчиков методов для приватных членов класса поиска. Даже если привилегированный код использует объект Lookup, проверка доступа ограничивается привилегиями исходного класса поиска.
Поиск может завершиться неудачей, потому что содержащий класс недоступен для класса поиска, или потому что нужный член класса отсутствует, или потому что нужный член класса недоступен для класса поиска, или потому что объект поиска недостаточно доверен для доступа к члену. В случае функции установки поля на поле final, принуждение к финальности рассматривается как своего рода контроль доступа, и поиск завершится неудачей, за исключением особых случаев Lookup.unreflectSetter. В любом из этих случаев будет брошено исключение ReflectiveOperationException при попытке поиска. Точный класс будет одним из следующих:
- NoSuchMethodException — если запрашивается метод, но он не существует
- NoSuchFieldException — если запрашивается поле, но оно не существует
- IllegalAccessException — если член существует, но проверка доступа завершается неудачей
В целом, условия, при которых обработчик методов может быть найден для метода M, не более ограничительны, чем условия, при которых класс поиска мог бы скомпилировать, проверить и разрешить вызов M. Там, где JVM подняла бы исключения, такие как NoSuchMethodError, поиск обработчика методов обычно поднимет соответствующее проверяемое исключение, такое как NoSuchMethodException. И эффект вызова обработчика методов, полученного в результате поиска, точно эквивалентен выполнению скомпилированного, проверенного и разрешенного вызова M. Та же точка справедлива для полей и конструкторов.
Обсуждение: Проверки доступа применяются только к именованным и отражённым методам, конструкторам и полям. Другие методы создания обработчиков методов, такие как MethodHandle.asType, не требуют проверок доступа и используются независимо от любого объекта Lookup .
Если необходимый член — protected, применяются стандартные правила JVM, включая требование, что класс поиска должен находиться в том же пакете, что и необходимый член, или унаследовать его. (См. спецификацию Java Virtual Machine, разделы 4.9.2, 5.4.3.5 и 6.4.) Кроме того, если необходимый член — это нестатическое поле или метод в другом пакете, полученный дескриптор метода может быть применен только к объектам класса поиска или одному из его подклассов. Это требование обеспечивается сужением типа ведущего параметра this с C (который обязательно является суперклассом класса поиска) до самого класса поиска.
JVM накладывает аналогичное требование на инструкцию invokespecial, требуя, чтобы аргумент получателя соответствовал как разрешенному методу, так и текущему классу. Опять же, это требование обеспечивается сужением типа ведущего параметра до полученного дескриптора метода. (См. спецификацию Java Virtual Machine, раздел 4.10.1.9.)
JVM представляет конструкторы и блоки статической инициализации как внутренние методы со специальными именами ("<init>" и "<clinit>"). Внутренний синтаксис инструкций вызова позволяет им ссылаться на такие внутренние методы так, как если бы они были обычными методами, но верификатор байткода JVM их отвергает. Поиск такого внутреннего метода вернет NoSuchMethodException.
Если отношение между вложенными типами выражено напрямую через атрибуты NestHost и NestMembers (см. спецификацию Java Virtual Machine, разделы 4.7.28 и 4.7.29), тогда связанный объект Lookup обеспечивает прямой доступ к классу поиска и всем его вложенным классам (см. Class.getNestHost). В противном случае доступ между вложенными классами обеспечивается компилятором Java, создающим оберточный метод для доступа к закрытому методу другого класса в том же вложении. Например, вложенный класс C.D может получить доступ к закрытым членам в других связанных классах, таких как C, C.D.E, или C.B, но компилятор Java может потребоваться сгенерировать оберточные методы в этих связанных классах. В таких случаях объект Lookup в C.E не смог бы получить доступ к этим закрытым членам. Решением этой проблемы является метод Lookup.in, который может преобразовать поиск в C.E в поиск в любой из этих других классов без специального повышения привилегий.
Доступ, разрешенный данному объекту поиска, может быть ограничен, в соответствии с его набором lookupModes, до подмножества членов, обычно доступных классу поиска. Например, метод publicLookup создает объект поиска, которому разрешен доступ только к общедоступным членам в общедоступных классах экспортированных пакетов. Метод lookup, чувствительный к вызывающему элементу, создает объект поиска с полными возможностями относительно класса вызывающего элемента, чтобы имитировать все поддерживаемые поведения байткода. Также метод Lookup.in может создавать объект поиска с меньшим количеством режимов доступа, чем исходный объект поиска.
Обсуждение доступа к частным членам и модулям: Мы говорим, что поиск имеет частный доступ, если его режимы поиска включают возможность доступа к private членам (включая закрытые члены вложенных классов). Как документировано в соответствующих методах в других местах, только поиски с частным доступом обладают следующими возможностями:
- доступ к закрытым полям, методам и конструкторам класса поиска и его вложенных классов
- создание дескрипторов методов, которые выполняют инструкции
emulate invokespecial - обход проверок доступа к пакетам для классов, доступных классу поиска
- создание
delegated lookup objectsс частным доступом к другим классам в том же члене пакета
Аналогично, поиск с модульным доступом гарантирует, что исходный создатель поиска был членом того же модуля, что и класс поиска.
Частный и модульный доступ определяются независимо; поиск может иметь один или оба, или ни одного. Поиск, который обладает обоими режимами доступа, называется обладающим полным доступом с привилегиями.
Поиск с исходным доступом гарантирует, что этот поиск создан исходным классом поиска и вызываемым bootstrap-методом JVM. Такой поиск с исходным доступом также имеет частный и модульный доступ, который имеет следующие дополнительные возможности:
- создание дескрипторов методов, которые вызывают методы, чувствительные к вызывающему элементу, такие как
Class.forName - получение данных класса, связанных с классом поиска
Каждое из этих разрешений является следствием того, что объект поиска с частным доступом может быть безопасно прослежен до исходного класса, чьи поведения байткода и разрешения доступа языка Java могут быть надежно определены и смоделированы дескрипторами методов.
Межмодульные поиски
Когда класс поиска в одном модулеM1 обращается к классу в другом модуле M2, выполняется дополнительная проверка доступа, помимо битов режима доступа. Lookup с режимом PUBLIC и классом поиска в M1 может получить доступ к общедоступным типам в M2, когда M2 доступен для M1 и когда тип находится в пакете M2 и экспортируется как минимум в M1. Lookup на C также может переместиться к целевому классу с помощью методов Lookup.in и MethodHandles.privateLookupIn. Перемещение через модули всегда записывает исходный класс поиска как предыдущий класс поиска и отключает доступ MODULE. Если целевой класс находится в том же модуле, что и класс поиска C, тогда целевой класс становится новым классом поиска и предыдущий класс поиска не меняется. Если целевой класс находится в другом модуле, отличном от модуля класса поиска M1 (модуля C), C становится новым предыдущим классом поиска, а целевой класс — новым классом поиска. В этом случае, если уже существует предыдущий класс поиска в M0, и он отличается от M1 и M2, тогда полученный поиск теряет все привилегии. Например,
Lookup lookup = MethodHandles.lookup(); // in class C Lookup lookup2 = lookup.in(D.class); MethodHandle mh = lookup2.findStatic(E.class, "m", MT);
Фабричный метод MethodHandles.lookup() создает объект Lookup с null предыдущим классом поиска. lookup.in(D.class) преобразует lookup в классе C в класс D без повышения привилегий. Если C и D находятся в одном модуле, lookup2 записывает D в качестве нового класса поиска и сохраняет тот же предыдущий класс поиска, что и исходный lookup, или null, если он не присутствует.
При перемещении Lookup из одного вложения в другое, доступ PRIVATE отключается. При перемещении Lookup из одного пакета в другой, отключается доступ PACKAGE. При перемещении Lookup из одного модуля в другой, отключается доступ MODULE. Перемещение через модули отключает возможность доступа к неэкспортированным классам как в модуле нового класса поиска, так и в модуле старого класса поиска, и результирующий Lookup остается только с доступом PUBLIC. Lookup может перемещаться туда и обратно в класс в модуле класса поиска и модуле предыдущего класса поиска. Перемещение через модули может только уменьшить доступ, но не увеличить его. Перемещение в некоторый третий модуль отключает все виды доступа.
В приведенном выше примере, если C и D находятся в разных модулях, lookup2 записывает D как класс поиска и C как предыдущий класс поиска, и lookup2 имеет только доступ PUBLIC. lookup2 может перемещаться к другим классам в модуле C и модуле D. Если класс E находится в третьем модуле, lookup2.in(E.class) создает Lookup для E без доступа, и класс поиска lookup2 D записывается в качестве предыдущего класса поиска.
Перемещение через модули ограничивает доступ к общедоступным типам, к которым могут одинаково получить доступ как класс поиска, так и предыдущий класс поиска (см. ниже).
MethodHandles.privateLookupIn(T.class, lookup) можно использовать для перемещения lookup из класса C в класс T и создания нового Lookup с приватным доступом, если класс поиска разрешено выполнять глубокий рефлексию над T. lookup должен иметь MODULE и PRIVATE доступ для вызова privateLookupIn. Модуль lookup в модуле M1 разрешено выполнять глубокий рефлексию над всеми классами в M1. Если T находится в M1, privateLookupIn создает новый Lookup по T с полными возможностями. Модуль lookup в C также разрешено выполнять глубокий рефлексию над T в другом модуле M2, если M1 читает M2 и M2 opens пакет, содержащий T, по крайней мере, до M1. T становится новым классом поиска, а C — новым предыдущим классом поиска, и доступ MODULE удаляется из полученного Lookup. Полученный Lookup можно использовать для поиска членов или перехода к другому классу поиска, вызвав Lookup::in. Но его нельзя использовать для получения другого приватного Lookup вызвав privateLookupIn, так как у него нет MODULE доступа.
Проверка доступа между модулями
Lookup с PUBLIC или UNCONDITIONAL режимом разрешает межмодульный доступ. Проверка доступа выполняется относительно класса поиска и предыдущего класса поиска, если он есть. Lookup с UNCONDITIONAL режимом может получить доступ к публичным типам во всех модулях, когда тип находится в пакете, который экспортирован безусловно.
Если Lookup по LC в M1 не имеет предыдущего класса поиска, поиск с PUBLIC режимом может получить доступ ко всем публичным типам в модулях, которые читаемы для M1, и тип находится в пакете, экспортированном по крайней мере для M1.
Если Lookup по LC в M1 имеет предыдущий класс поиска PLC по M0, поиск с PUBLIC режимом может получить доступ к пересечению всех публичных типов, доступных для M1 и всех публичных типов, доступных для M0. M0 читает M1, и поэтому множество доступных типов включает:
Типы, равнодоступные для M0 и M1
|
|---|
Безусловно экспортированные пакеты из M1
|
Безусловно экспортированные пакеты из M0 если M1 читает M0
|
Безусловно экспортированные пакеты из третьего модуля M2 если оба M0 и M1 читают M2
|
Квалифицированные экспортированные пакеты из M1 в M0
|
Квалифицированные экспортированные пакеты из M0 в M1 если M1 читает M0
|
Квалифицированные экспортированные пакеты из третьего модуля M2 в оба M0 и M1 если оба M0 и M1 читают M2
|
Режимы доступа
В таблице ниже показаны режимы доступаLookup , полученного любым из следующих методов фабрики или преобразования: | Объект поиска | Оригинальный | Защищенный | Приватный | Пакет | Модуль | Публичный |
|---|---|---|---|---|---|---|
CL = MethodHandles.lookup() в C
| ORI | PRO | PRI | PAC | MOD | 1R |
CL.in(C1) в том же пакете | PAC | MOD | 1R | |||
CL.in(C1) в том же модуле | MOD | 1R | ||||
CL.in(D) в другом модуле | 2R | |||||
CL.in(D).in(C) вернуться в модуль | 2R | |||||
PRI1 = privateLookupIn(C1,CL) | PRO | PRI | PAC | MOD | 1R | |
PRI1a = privateLookupIn(C,PRI1) | PRO | PRI | PAC | MOD | 1R | |
PRI1.in(C1) в том же пакете | PAC | MOD | 1R | |||
PRI1.in(C1) в другом пакете | MOD | 1R | ||||
PRI1.in(D) в другом модуле | 2R | |||||
PRI1.dropLookupMode(PROTECTED) | PRI | PAC | MOD | 1R | ||
PRI1.dropLookupMode(PRIVATE) | PAC | MOD | 1R | |||
PRI1.dropLookupMode(PACKAGE) | MOD | 1R | ||||
PRI1.dropLookupMode(MODULE) | 1R | |||||
PRI1.dropLookupMode(PUBLIC) | нет | |||||
PRI2 = privateLookupIn(D,CL) | PRO | PRI | PAC | 2R | ||
privateLookupIn(D,PRI1) | PRO | PRI | PAC | 2R | ||
privateLookupIn(C,PRI2) не удалось | IAE | |||||
PRI2.in(D2) в том же пакете | PAC | 2R | ||||
PRI2.in(D2) в другом пакете | 2R | |||||
PRI2.in(C1) вернуться в модуль | 2R | |||||
PRI2.in(E) перейти в третий модуль | нет | |||||
PRI2.dropLookupMode(PROTECTED) | PRI | PAC | 2R | |||
PRI2.dropLookupMode(PRIVATE) | PAC | 2R | ||||
PRI2.dropLookupMode(PACKAGE) | 2R | |||||
PRI2.dropLookupMode(MODULE) | 2R | |||||
PRI2.dropLookupMode(PUBLIC) | нет | |||||
CL.dropLookupMode(PROTECTED) | PRI | PAC | MOD | 1R | ||
CL.dropLookupMode(PRIVATE) | PAC | MOD | 1R | |||
CL.dropLookupMode(PACKAGE) | MOD | 1R | ||||
CL.dropLookupMode(MODULE) | 1R | |||||
CL.dropLookupMode(PUBLIC) | нет | |||||
PUB = publicLookup() | У | |||||
PUB.in(D) в другом модуле | У | |||||
PUB.in(D).in(E) третий модуль | У | |||||
PUB.dropLookupMode(UNCONDITIONAL) | нет | |||||
privateLookupIn(C1,PUB) не удалось | IAE | |||||
ANY.in(X), для недоступного X
| нет |
Примечания:
- Классы
CиC1находятся в модулеM1, ноDиD2находятся в модулеM2, аEнаходится в модулеM3.Xобозначает класс, который недоступен для поиска.ANYобозначает любой из примеров поиска. -
ORIуказывает на установленный битORIGINAL,PROуказывает на установленный битPROTECTED,PRIуказывает на установленный битPRIVATE,PACуказывает на установленный битPACKAGE,MODуказывает на установленный битMODULE,1Rи2Rуказывают на установленный битPUBLIC,Uуказывает на установленный битUNCONDITIONAL,IAEуказывает на исключениеIllegalAccessException. - Доступ к публичным членам бывает трех типов:
- безусловный (
U): поиск предполагает возможность чтения. У запроса естьnullпредыдущий класс поиска. - чтение в одном модуле (
1R): проверка доступа модуля выполняется относительно класса поиска. У запроса естьnullпредыдущий класс поиска. - чтение в двух модулях (
2R): проверка доступа модуля выполняется относительно класса поиска и предыдущего класса поиска. У запроса есть непустой предыдущий класс поиска, находящийся в другом модуле по сравнению с текущим классом поиска.
- безусловный (
- Любая попытка обратиться к третьему модулю теряет весь доступ.
- Если целевой класс
Xнедоступен дляLookup::in, все режимы доступа отменяются.
Взаимодействие с менеджером безопасности
Хотя инструкции байткода могут ссылаться только на классы в связанном загрузчике классов, этот API может искать методы в любом классе, если доступен ссылка на егоClass объект. Такие ссылки между загрузчиками также возможны с API Core Reflection, но недоступны инструкциям байткода, таким как invokestatic или getfield. Для проверки таких переходов между загрузчиками классов в приложениях существует API менеджера безопасности. Эти проверки применимы как к API MethodHandles.Lookup , так и к API Core Reflection (как в Class). Если менеджер безопасности присутствует, поиск членов и классов подвергается дополнительным проверкам. Выполняется от одного до трех вызовов менеджера безопасности. Любой из этих вызовов может отклонить доступ, выбросив исключение SecurityException. Пусть smgr — менеджер безопасности, lookc — класс поиска текущего объекта поиска, refc — содержащий класс, в котором ищется член, и defc — класс, в котором член фактически определён. (Если доступен класс или другой тип, то значения refc и defc — сам класс.) Значение lookc определяется как не присутствующее, если текущий объект поиска не имеет полного доступа к привилегиям. Вызовы выполняются в соответствии со следующими правилами:
-
Шаг 1: Если
lookcотсутствует или его загрузчик классов не совпадает с загрузчиком классовrefcили не является его предком, тогда вызываетсяsmgr.checkPackageAccess(refcPkg), гдеrefcPkg— пакетrefc. -
Шаг 2a: Если полученный член не является общедоступным и
lookcотсутствует, тогда вызываетсяsmgr.checkPermissionсRuntimePermission("accessDeclaredMembers"). -
Шаг 2b: Если полученный класс имеет загрузчик классов
null, иlookcотсутствует, тогда вызываетсяsmgr.checkPermissionсRuntimePermission("getClassLoader"). -
Шаг 3: Если полученный член не является общедоступным,
lookcотсутствует, иdefcиrefcразличаются, тогда вызываетсяsmgr.checkPackageAccess(defcPkg), гдеdefcPkg— пакетdefc.
Если менеджер безопасности присутствует и текущий объект поиска не имеет полных привилегий доступа, то вызовы defineClass, defineHiddenClass, defineHiddenClassWithClassData вызывают smgr.checkPermission с RuntimePermission("defineClass").
Методы, чувствительные к вызывающему объекту
Небольшое количество методов Java обладает специальным свойством, называемым чувствительностью к вызывающему объекту. Метод, чувствительный к вызывающему объекту, может вести себя по-разному в зависимости от идентификатора своего непосредственного вызывающего объекта.Если запрашивается обработчик метода, чувствительного к вызывающему объекту, применяются общие правила поведения байткода bytecode behaviors, но они учитывают класс поиска особым образом. Результирующий обработчик метода ведет себя так, как будто он был вызван инструкцией, содержащейся в классе поиска, чтобы метод, чувствительный к вызывающему объекту, обнаружил класс поиска. (При этом вызывающий объект обработчика метода игнорируется.) Таким образом, в случае методов, чувствительных к вызывающему объекту, разные классы поиска могут приводить к поведению обработчиков методов, отличающемуся по результатам.
В случаях, когда объект поиска является publicLookup() или каким-либо другим объектом поиска без оригинального доступа, класс поиска игнорируется. В таких случаях обработчик метода, чувствительного к вызывающему объекту, не может быть создан, доступ запрещен, и поиск завершается с ошибкой IllegalAccessException.
Обсуждение: Например, метод, чувствительный к вызывающему объекту, Class.forName(x), может возвращать различные классы или выбрасывать различные исключения в зависимости от загрузчика классов класса, который его вызывает. Общедоступный поиск Class.forName завершится неудачей, поскольку нет разумного способа определить его поведение байткода.
Если приложение кэширует обработчики методов для широкого обмена, оно должно использовать publicLookup() для их создания. Если происходит поиск Class.forName, он завершится неудачей, и приложение должно предпринять соответствующие действия в этом случае. Возможно, что более поздний поиск, возможно, во время вызова метода загрузки, может включить конкретный идентификатор вызывающего объекта, сделав метод доступным.
Функция MethodHandles.lookup является чувствительной к вызывающему объекту, чтобы обеспечить надежную основу для поиска. Почти все остальные методы API JSR 292 полагаются на объекты поиска для проверки запросов на доступ.
Краткое описание вложенных классов
| Модификатор и тип | Класс | Описание |
|---|---|---|
static enum |
MethodHandles.Lookup.ClassOption |
Набор параметров класса, которые указывают, добавляется ли динамически созданный с помощью метода Lookup::defineHiddenClass скрытый класс как новый член вложенного класса и/или имеет ли скрытый класс тесную связь с загрузчиком классов, отмеченным как его определяющий загрузчик. |
Краткое описание полей
| Модификатор и тип | Поле | Описание |
|---|---|---|
static final int |
MODULE |
Однобитовая маска, представляющая доступ module, который может влиять на результат lookupModes. |
static final int |
ORIGINAL |
Однобитовая маска, представляющая доступ original, который может влиять на результат lookupModes. |
static final int |
PACKAGE |
Однобитовая маска, представляющая доступ package (доступ по умолчанию), который может влиять на результат lookupModes. |
static final int |
PRIVATE |
Однобитовая маска, представляющая доступ private, который может влиять на результат lookupModes. |
static final int |
PROTECTED |
Однобитовая маска, представляющая доступ protected, который может влиять на результат lookupModes. |
static final int |
PUBLIC |
Однобитовая маска, представляющая доступ public, который может влиять на результат lookupModes. |
static final int |
UNCONDITIONAL |
Однобитовая маска, представляющая доступ unconditional, который может влиять на результат lookupModes. |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
Class<?> |
accessClass |
Определяет, можно ли получить доступ к классу из контекста поиска, определенного этим объектом Lookup. |
MethodHandle |
bind |
Создает обработчик метода со связыванием на этапе компиляции для нестатического метода. |
Class<?> |
defineClass |
Создает и связывает класс или интерфейс из bytes с тем же загрузчиком классов и в том же пакете времени выполнения и областью защиты, что и класс поиска этого поиска класс поиска, как при вызове ClassLoader::defineClass. |
MethodHandles.Lookup |
defineHiddenClass |
Создает скрытый класс или интерфейс из bytes, возвращая Lookup для вновь созданного класса или интерфейса. |
MethodHandles.Lookup |
defineHiddenClassWithClassData |
Создает скрытый класс или интерфейс из bytes с присоединенными данными класса, возвращая Lookup для вновь созданного класса или интерфейса. |
MethodHandles.Lookup |
dropLookupMode |
Создает поиск в том же классе поиска, в котором этот объект поиска находит члены, но с режимом поиска, который потерял данный режим поиска. |
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 modifier bit. Объект с этим режимом поиска выполняет проверку доступа между модулями относительно класса поиска lookup class и предыдущего класса поиска previous lookup class, если он присутствует.
- См. также:
PRIVATE
public static final int PRIVATE
private, который может повлиять на результат lookupModes. Значение, 0x02, совпадает со значением бита модификатора private modifier bit.- См. также:
PROTECTED
public static final int PROTECTED
protected, который может повлиять на результат lookupModes. Значение, 0x04, совпадает со значением бита модификатора protected modifier bit.- См. также:
PACKAGE
public static final int PACKAGE
package (доступ по умолчанию), который может повлиять на результат lookupModes. Значение равно 0x08, которое не соответствует ни одному конкретному биту модификатора.- См. также:
MODULE
public static final int MODULE
module, который может повлиять на результат lookupModes. Значение равно 0x10, которое не соответствует ни одному конкретному биту модификатора. В сочетании с битом модификатора PUBLIC, объект с этим режимом поиска может получить доступ ко всем публичным типам в модуле класса поиска и публичным типам в пакетах, экспортированных другими модулями в модуль класса поиска. Если этот режим поиска установлен, предыдущий класс поиска previous lookup class всегда null.
- С:
- 9
- См. также:
БЕЗУСЛОВНЫЙ
public static final int UNCONDITIONAL
unconditional, который может повлиять на результат lookupModes. Значение равно 0x20, которое не соответствует ни одному конкретному биту модификатора. Объект с этим режимом поиска предполагает чтение. Этот режим поиска может получить доступ ко всем публичным членам публичных типов всех модулей, когда тип находится в пакете, который exported unconditionally. Если этот режим поиска установлен, предыдущий класс поиска previous lookup class всегда null.
- С:
- 9
- См. также:
ИСТОЧНИК
public static final int ORIGINAL
original, который может повлиять на результат lookupModes. Значение равно 0x40, которое не соответствует ни одному конкретному биту модификатора. Если этот режим поиска установлен, объект Lookup должен быть создан исходным классом поиска, вызвав метод MethodHandles.lookup() или методом инициализации, вызванным виртуальной машиной. Объект Lookup с этим режимом поиска имеет полный привилегированный доступ.
- С:
- 16
- См. также:
Подробное описание методов
lookupClass
public Class<?> lookupClass()
Если у этого объекта поиска есть предыдущий класс поиска, проверки доступа выполняются как для класса поиска, так и для предыдущего класса поиска.
Класс предполагает максимальный уровень разрешения на доступ, но разрешения могут быть дополнительно ограничены битовой маской lookupModes, которая управляет тем, можно ли получить доступ к непубличным членам.
- Возвращает:
- класс поиска, от имени которого этот объект поиска находит члены
- См. также:
previousLookupClass
public Class<?> previousLookupClass()
null. Объект Lookup, созданный методами-фабриками, такими как метод lookup() и publicLookup(), имеет null предыдущий класс поиска. Объект Lookup имеет непустой предыдущий класс поиска, когда этот поиск был перенесен из старого класса поиска в одном модуле в новый класс поиска в другом модуле.
- Возвращает:
- класс поиска в другом модуле, из которого этот объект поиска был ранее перемещен, или
null - С:
- 14
- См. также:
режимыПоиска
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является примитивным типом или пустым или массивом классов -
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 — это байты класса допустимого файла класса (как определено в Спецификации виртуальной машины Java) с именем класса в том же пакете, что и класс поиска.
Этот метод не выполняет инициализатор класса. Инициализатор класса может быть выполнен в более позднее время, как подробно описано в разделе 12.4 Спецификации языка Java.
Если присутствует менеджер безопасности и у этого поиска нет полного привилегированного доступа, сначала вызывается его метод checkPermission для проверки RuntimePermission("defineClass").
- Parameters:
-
bytes- байты класса - Returns:
- объект
Classдля класса - Throws:
-
IllegalAccessException- если у этого поиска нет доступаPACKAGE -
ClassFormatError- еслиbytesне является структуройClassFile -
IllegalArgumentException- еслиbytesобозначает класс в другом пакете, чем класс поиска, илиbytesне является классом или интерфейсом (флагACC_MODULEустановлен в значении элементаaccess_flags) -
VerifyError- если вновь созданный класс не может быть проверен -
LinkageError- если вновь созданный класс не может быть связан по какой-либо другой причине -
SecurityException- если менеджер безопасности присутствует и он отказывает в доступе -
NullPointerException- еслиbytes—null - Since:
- 9
- See Also:
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— бинарное имя, полученное путём взятияN(бинарного имени, закодированного во внутреннем формате) и замены косой черты ASCII точкой ASCII. В случаеClass, представляющегоC,-
Class.getName()возвращает строкуGN + "/" + <suffix>, даже если это не является допустимым бинарным именем класса или интерфейса. -
Class.descriptorString()возвращает строку"L" + N + "." + <suffix> + ";", даже если это не является допустимым именем описателя типа. -
Class.describeConstable()возвращает пустой необязательный параметр, так какCне может быть описан в номинальной форме.
-
- Постоянная, указанная
После того, как C будет выведен, он будет связан виртуальной машиной Java. Связывание происходит так, как указано в JVMS 5.4.3, с следующими корректировками:
- Во время проверки, когда необходимо загрузить класс с именем
CN, попытка завершается успешно, создавая классC. Никакие запросы к загрузчику классов не производятся. - При любой попытке разрешить запись в пуле постоянных времени выполнения, указанную
this_class, символическая ссылка считается разрешенной доC, и разрешение всегда происходит мгновенно.
Если параметр initialize равен true, то C инициализируется виртуальной машиной Java.
Созданный класс или интерфейс C служит классом поиска Lookup объекта, возвращённого этим методом. C является скрытым в том смысле, что никакой другой класс или интерфейс не может обратиться к C через запись в пуле постоянных. То есть, скрытый класс или интерфейс не может быть назван в качестве супертипа, типа поля, типа параметра метода или типа возвращаемого значения любым другим классом. Это связано с тем, что скрытый класс или интерфейс не имеет бинарного имени, поэтому нет внутреннего представления, которое можно записать в пуле постоянных какого-либо класса. Скрытый класс или интерфейс недоступен для Class.forName(String, boolean, ClassLoader), ClassLoader.loadClass(String, boolean) или findClass(String) и не может быть изменён агентами Java или инструментальными агентами, использующими JVM Tool Interface.
Класс или интерфейс, созданный загрузчиком классов, имеет тесную связь с этим загрузчиком. То есть, каждый объект Class содержит ссылку на загрузчик ClassLoader, который его определил. Это означает, что класс, созданный загрузчиком классов, может быть разгружен только в том случае, если его определяющий загрузчик недоступен и, следовательно, может быть удалён сборщиком мусора (JLS 12.7). Однако по умолчанию скрытый класс или интерфейс может быть разгружен, даже если загрузчик классов, отмеченный в качестве его определяющего загрузчика, доступен. Это поведение полезно, когда скрытый класс или интерфейс обслуживает несколько классов, определённых произвольными загрузчиками классов. В других случаях скрытый класс или интерфейс может быть связан с одним классом (или небольшим количеством классов) с тем же определяющим загрузчиком, что и скрытый класс или интерфейс. В таких случаях, когда скрытый класс или интерфейс должен совпадать по времени с обычным классом или интерфейсом, опция STRONG может быть передана в options. Это обеспечивает, чтобы скрытый класс имел ту же тесную связь с загрузчиком классов, отмеченным как его определяющий загрузчик, что и обычный класс или интерфейс со своим определяющим загрузчиком. Если STRONG не используется, то вызывающий defineHiddenClass по-прежнему может предотвратить разгрузку скрытого класса или интерфейса, гарантируя, что объект Class доступен.
Характеристики разгрузки устанавливаются для каждого скрытого класса при его определении и не могут быть изменены позже. Преимущество разрешения разгрузки скрытых классов независимо от загрузчика классов, отмеченного как их определяющий загрузчик, заключается в том, что приложение может создать очень большое количество скрытых классов. В противном случае, если STRONG используется, у JVM может закончиться память, как если бы обычные классы были созданы загрузчиками классов.
Классы и интерфейсы в одном наборе допускают взаимный доступ к своим закрытым членам. Связь наборов определяется атрибутом NestHost (JVMS 4.7.28) и атрибутом NestMembers (JVMS 4.7.29) в файле class. По умолчанию скрытый класс принадлежит набору, состоящему только из него самого, потому что скрытый класс не имеет бинарного имени. Опция NESTMATE может быть передана в options для создания скрытого класса или интерфейса C как члена набора. Набор, которому принадлежит C, не основан на атрибуте NestHost в структуре ClassFile файла, из которого C был выведен. Вместо этого следующие правила определяют хост набора C:
- Если хост набора класса поиска данного
Lookupбыл ранее определён, то пустьHбудет хостом набора класса поиска. В противном случае хост набора класса поиска определяется по алгоритму JVMS 5.4.4, что даётH. - Хост набора
Cопределяется какH, хост набора класса поиска.
Скрытый класс или интерфейс может быть сериализуемым, но это требует специального механизма сериализации, чтобы гарантировать правильную сериализацию и десериализацию экземпляров. Механизм сериализации по умолчанию поддерживает только классы и интерфейсы, которые могут быть найдены по их имени класса.
- Параметры:
-
bytes- байты, составляющие данные класса, в формате допустимогоclassфайла, как определено в Спецификации виртуальной машины Java. -
initialize- еслиtrueкласс будет инициализирован. -
options- параметры класса - Возвращает:
- объект
Lookupскрытого класса с исходным и полным доступом - Исключение:
-
IllegalAccessException- если у этогоLookupнет полного доступа -
SecurityException- если менеджер безопасности присутствует и он отказывает в доступе -
ClassFormatError- еслиbytesне является структуройClassFile -
UnsupportedClassVersionError- еслиbytesне соответствует поддержанной мажорной или минорной версии -
IllegalArgumentException- еслиbytesобозначает класс в другом пакете, чем класс поиска, илиbytesне является классом или интерфейсом (флагACC_MODULEустановлен в значении элементаaccess_flags) -
IncompatibleClassChangeError- если класс или интерфейс, указанный как непосредственный суперклассC, на самом деле является интерфейсом, или если любой из классов или интерфейсов, указанных как непосредственные суперинтерфейсыC, на самом деле не является интерфейсом -
ClassCircularityError- если любой из суперклассов или суперинтерфейсовCявляетсяCсамим собой -
VerifyError- если созданный класс не может быть проверен -
LinkageError- если созданный класс не может быть связан по другим причинам -
NullPointerException- если любой параметрnull - См. Спецификацию языка Java:
- 12.7 Выгрузка классов и интерфейсов
- См. Спецификацию виртуальной машины Java:
- 4.2.1 Имена бинарных классов и интерфейсов
4.2.2 Неопределенные имена
4.7.28 АтрибутNestHost
4.7.29 АтрибутNestMembers
5.4.3.1 Разрешение классов и интерфейсов
5.4.4 Контроль доступа
5.3.5 ПолучениеClassиз представления файлаclass
5.4 Связывание
5.5 Инициализация
- С:
- 15
- См. также:
defineHiddenClassWithClassData
public MethodHandles.Lookup defineHiddenClassWithClassData(byte[] bytes, Object classData, boolean initialize, MethodHandles.Lookup.ClassOption... options) throws IllegalAccessException
bytes с ассоциированными данными класса, возвращая Lookup для нового класса или интерфейса. Этот метод эквивалентен вызову defineHiddenClass(bytes, initialize, options) как если бы скрытый класс был введён с приватным статическим конечным неопределённым полем, инициализированным заданными classData в первой инструкции инициализатора класса. Созданный класс связывается виртуальной машиной Java.
Методы MethodHandles::classData и MethodHandles::classDataAt могут быть использованы для получения classData.
- Примечание API:
- Фреймворк может создать скрытый класс с данными класса с одним или несколькими объектами и загрузить данные класса как динамически вычисленные константы через метод запуска.
Class dataдоступен только объекту поиска, созданному новым скрытым классом, но недоступен другим членам в том же вложении (в отличие от приватных статических полей, доступных сотоварищам по вложению). Следует проявлять осторожность в отношении изменяемости, например, при передаче массива или другой изменяемой структуры через данные класса. Изменение любых значений, хранящихся в данных класса во время выполнения, может привести к непредсказуемому поведению. Если данные класса являютсяList, рекомендуется сделать их неизменяемыми, например, черезList::of. - Параметры:
-
bytes- байты класса -
classData- предварительно инициализированные данные класса -
initialize- еслиtrueкласс будет инициализирован. -
options- параметры класса - Возвращает:
- объект
Lookupскрытого класса с исходным и полным доступом - Исключение:
-
IllegalAccessException- если у этогоLookupнет полного доступа -
SecurityException- если менеджер безопасности присутствует и он отказывает в доступе -
ClassFormatError- еслиbytesне является структуройClassFile -
UnsupportedClassVersionError- еслиbytesне соответствует поддержанной мажорной или минорной версии -
IllegalArgumentException- еслиbytesобозначает класс в другом пакете, чем класс поиска, илиbytesне является классом или интерфейсом (флагACC_MODULEустановлен в значении элементаaccess_flags) -
IncompatibleClassChangeError- если класс или интерфейс, указанный как непосредственный суперклассC, на самом деле является интерфейсом, или если любой из классов или интерфейсов, указанных как непосредственные суперинтерфейсыC, на самом деле не является интерфейсом -
ClassCircularityError- если любой из суперклассов или суперинтерфейсовCявляетсяCсамим собой -
VerifyError- если созданный класс не может быть проверен -
LinkageError- если созданный класс не может быть связан по другим причинам -
NullPointerException- если любой параметрnull - См. Спецификацию языка Java:
- 12.7 Выгрузка классов и интерфейсов
- См. Спецификацию виртуальной машины Java:
- 4.2.1 Имена бинарных классов и интерфейсов
4.2.2 Неопределенные имена
4.7.28 АтрибутNestHost
4.7.29 АтрибутNestMembers
5.4.3.1 Разрешение классов и интерфейсов
5.4.4 Контроль доступа
5.3.5 ПолучениеClassиз представления файлаclass
5.4 Связывание
5.5 Инициализация
- С:
- 16
- См. также:
toString
public String toString()
Class.getName.) Если на доступ к этому поиску есть ограничения, это обозначается добавлением суффикса к имени класса, состоящего из косой черты и ключевого слова. Ключевое слово представляет собой наиболее строгий разрешенный доступ и выбирается следующим образом: - Если доступ запрещен, суффикс — «/noaccess».
- Если разрешен только безусловный доступ, суффикс — «/publicLookup».
- Если разрешен только публичный доступ к типам в экспортированных пакетах, суффикс — «/public».
- Если разрешен только публичный и модульный доступ, суффикс — «/module».
- Если разрешен публичный и пакетный доступ, суффикс — «/package».
- Если разрешены публичный, пакетный и частный доступ, суффикс — «/private».
MethodHandles.lookup. Объекты, созданные Lookup.in, всегда имеют ограниченный доступ и отображают суффикс. (Может показаться странным, что защищенный доступ сильнее, чем частный. Если рассматривать его независимо от пакетного доступа, то защищенный доступ первым теряется, потому что он требует прямого наследования между вызывающим и вызываемым объектами.)
- Overrides:
-
toStringв классеObject - Возвращает:
- строковое представление объекта.
- См. также:
findStatic
public MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException
findVirtual или findSpecial.) Метод и все его типы аргументов должны быть доступны объекту поиска. Возвращаемый обработчик метода будет иметь переменную арность, если и только если бит переменной арности метода (0x0080) установлен.
При вызове возвращаемого обработчика метода класс метода будет инициализирован, если он ещё не был инициализирован.
Пример:
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle MH_asList = publicLookup().findStatic(Arrays.class, "asList", methodType(List.class, Object[].class)); assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
- Параметры:
-
refc- класс, из которого обращается к методу -
name- имя метода -
type- тип метода - Возвращает:
- необходимый обработчик метода
- Исключения:
-
NoSuchMethodException- если метод не существует -
IllegalAccessException- если проверка доступа не удалась, или если метод неstatic, или если бит переменной арности метода установлен и проверкаasVarargsCollectorне удалась -
SecurityException- если менеджер безопасности присутствует и им отказано в доступе -
NullPointerException- если любой аргумент равен null
findVirtual
public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException
refc) в начале. Метод и все его типы аргументов должны быть доступны объекту поиска. При вызове обработчик будет рассматривать первый аргумент как получатель и, для не-частных методов, производить диспетчеризацию на тип получателя, чтобы определить, какую реализацию метода использовать. Для частных методов вызывается метод с указанным именем в refc, на получателе. (Диспетчеризация идентична той, что выполняется инструкцией invokevirtual или invokeinterface)
Первый аргумент будет типа refc, если класс поиска имеет полные привилегии для доступа к элементу. В противном случае элемент должен быть protected, и первый аргумент будет ограничен типом до класса поиска.
Возвращаемый обработчик метода будет иметь переменную арность, если и только если бит переменной арности метода (0x0080) установлен.
Из-за общей эквивалентности инструкций invokevirtual и обработчиков методов, произведённых findVirtual, если класс MethodHandle, а строка имени соответствует invokeExact или invoke, результирующий обработчик метода эквивалентен обработчику, произведённому MethodHandles.exactInvoker или MethodHandles.invoker с тем же аргументом type.
Если класс VarHandle и строка имени соответствует имени метода с сигнатурно-полиморфным режимом доступа, результирующий обработчик метода эквивалентен обработчику, произведённому MethodHandles.varHandleInvoker(java.lang.invoke.VarHandle.AccessMode, java.lang.invoke.MethodType) с режимом доступа, соответствующим строке имени, и с теми же аргументами type.
Пример:
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle MH_concat = publicLookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class, "hashCode", methodType(int.class)); MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class, "hashCode", methodType(int.class)); assertEquals("xy", (String) MH_concat.invokeExact("x", "y")); assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy")); assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy")); // interface method: MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class, "subSequence", methodType(CharSequence.class, int.class, int.class)); assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString()); // constructor "internal method" must be accessed differently: MethodType MT_newString = methodType(void.class); //()V for new String() try { assertEquals("impossible", lookup() .findVirtual(String.class, "<init>", MT_newString)); } catch (NoSuchMethodException ex) { } // OK MethodHandle MH_newString = publicLookup() .findConstructor(String.class, MT_newString); assertEquals("", (String) MH_newString.invokeExact());
- Параметры:
-
refc- класс или интерфейс, из которого обращается к методу -
name- имя метода -
type- тип метода, без аргумента получателя - Возвращает:
- необходимый обработчик метода
- Исключения:
-
NoSuchMethodException- если метод не существует -
IllegalAccessException- если проверка доступа не удалась, или если методstatic, или если бит переменной арности метода установлен и проверкаasVarargsCollectorне удалась -
SecurityException- если менеджер безопасности присутствует и им отказано в доступе -
NullPointerException- если любой аргумент равен null
findConstructor
public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException
Требуемый тип должен иметь тип возврата void. (Это согласуется с обработкой JVM описателей типа конструктора.)
Возвращаемый обработчик метода будет иметь переменную арность, если и только если бит переменной арности конструктора (0x0080) установлен.
При вызове возвращаемого обработчика метода класс конструктора будет инициализирован, если он ещё не был инициализирован.
Пример:
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle MH_newArrayList = publicLookup().findConstructor( ArrayList.class, methodType(void.class, Collection.class)); Collection orig = Arrays.asList("x", "y"); Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig); assert(orig != copy); assertEquals(orig, copy); // a variable-arity constructor: MethodHandle MH_newProcessBuilder = publicLookup().findConstructor( ProcessBuilder.class, methodType(void.class, String[].class)); ProcessBuilder pb = (ProcessBuilder) MH_newProcessBuilder.invoke("x", "y", "z"); assertEquals("[x, y, z]", pb.command().toString());
- Параметры:
-
refc- класс или интерфейс, из которого обращается к методу -
type- тип метода, без аргумента получателя, с типом возврата void - Возвращает:
- необходимый обработчик метода
- Исключения:
-
NoSuchMethodException- если конструктор не существует -
IllegalAccessException- если проверка доступа не удалась или если бит переменной арности метода установлен и проверкаasVarargsCollectorне удалась -
SecurityException- если менеджер безопасности присутствует и им отказано в доступе -
NullPointerException- если любой аргумент равен null
findClass
public Class<?> findClass(String targetName) throws ClassNotFoundException, IllegalAccessException
Lookup, как если бы он был решён инструкцией ldc. Такой поиск, как указано в JVMS 5.4.3.1, пытается найти и загрузить класс, а затем определяет, доступен ли класс для этого объекта поиска. Контекст поиска определяется здесь классом поиска, его загрузчиком классов и режимами поиска.
- Параметры:
-
targetName- полное квалифицированное имя искомого класса. - Возвращает:
- запрашиваемый класс.
- Исключения:
-
SecurityException- если менеджер безопасности присутствует и им отказано в доступе -
LinkageError- если происходит сбой привязке -
ClassNotFoundException- если класс не может быть загружен загрузчиком класса поиска. -
IllegalAccessException- если класс недоступен, используя разрешенные режимы доступа. -
NullPointerException- еслиtargetNameравен null - См. Спецификацию виртуальной машины Java:
- 5.4.3.1 Разрешение классов и интерфейсов
- С:
- 9
ensureInitialized
public Class<?> ensureInitialized(Class<?> targetClass) throws IllegalAccessException
targetClass был инициализирован. Класс, подлежащий инициализации, должен быть доступен для этого объекта Lookup. Этот метод вызывает инициализацию targetClass, если она ещё не была выполнена, как указано в спецификации JVMS 5.5.- Параметры:
-
targetClass- класс, подлежащий инициализации - Возвращает:
-
targetClass, который был инициализирован - Изначает исключения:
-
IllegalArgumentException- еслиtargetClassявляется примитивным типом или классомvoidили массива -
IllegalAccessException- еслиtargetClassнедоступен для этого поиска -
ExceptionInInitializerError- если инициализация класса, вызванная этим методом, завершилась неудачей -
SecurityException- если менеджер безопасности присутствует и он отказывается предоставить доступ - См. Спецификацию виртуальной машины Java:
- 5.5 Инициализация
- С:
- 15
accessClass
public Class<?> accessClass(Class<?> targetClass) throws IllegalAccessException
Lookup. Статический инициализатор класса не выполняется. Если targetClass является классом массива, то targetClass доступен, если тип элемента класса массива доступен. В противном случае, доступность targetClass определяется следующим образом. Если targetClass находится в том же модуле, что и класс поиска, то класс поиска LC в модуле M1, а предыдущий класс поиска находится в модуле M0 или null, если он отсутствует, то targetClass доступен только в том случае, если выполняется одно из следующих условий:
- Если у этого поиска есть
PRIVATEдоступ, тоtargetClassявляетсяLCили другим классом в том же вложенном блокеLC. - Если у этого поиска есть
PACKAGEдоступ, тоtargetClassнаходится в той же рабочей папке, что иLC. - Если у этого поиска есть
MODULEдоступ, тоtargetClassявляется общедоступным типом вM1. - Если у этого поиска есть
PUBLICдоступ, тоtargetClassявляется общедоступным типом в пакете, экспортированномM1по крайней мере вM0, если предыдущий класс поиска присутствует; в противном случаеtargetClassявляется общедоступным типом в пакете, экспортированномM1безусловно.
В противном случае, если у этого поиска есть UNCONDITIONAL доступ, то этот поиск может получить доступ к общедоступным типам во всех модулях, когда тип находится в пакете, который экспортирован безусловно.
В противном случае, targetClass находится в другом модуле, чем lookupClass, и если у этого поиска нет PUBLIC доступа, то lookupClass недоступен.
В противном случае, если у этого поиска нет предыдущего класса поиска, M1 — это модуль, содержащий lookupClass, а M2 — это модуль, содержащий targetClass, то targetClass доступен только в том случае, если
-
M1считываетM2, и -
targetClassявляется общедоступным и находится в пакете, экспортированномM2по крайней мере вM1.
В противном случае, если у этого поиска есть предыдущий класс поиска, M1 и M2 такие же, как и раньше, а M0 — это модуль, содержащий предыдущий класс поиска, то targetClass доступен только в том случае, если одно из следующих условий истинно:
-
targetClassнаходится вM0иM1считываетM0и тип находится в пакете, экспортированном в по крайней мереM1. -
targetClassнаходится вM1иM0считываетM1и тип находится в пакете, экспортированном по крайней мере вM0. -
targetClassнаходится в третьем модулеM2иM0иM1считываютM2и тип находится в пакете, экспортированном в по крайней мереM0иM2.
В противном случае, targetClass недоступен.
- Параметры:
-
targetClass- класс, для которого проверяется доступ - Возвращает:
- класс, для которого была проверена доступность
- Изначает исключения:
-
IllegalAccessException- если класс недоступен из класса поиска и предыдущего класса поиска, если он присутствует, с использованием разрешенных режимов доступа. -
SecurityException- если менеджер безопасности присутствует и он отказывается предоставить доступ -
NullPointerException- еслиtargetClassявляетсяnull - С:
- 9
- См. также:
findSpecial
public MethodHandle findSpecial(Class<?> refc, String name, MethodType type, Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException
invokespecial внутри явно указанного specialCaller. Тип дескриптора метода будет соответствовать методу с надлежащим образом ограниченным типом получателя, добавленным в начало. (Тип получателя будет specialCaller или его подтипом.) Метод и все его типы аргументов должны быть доступны для объекта поиска. Перед разрешением метода, если явно указанный класс вызывающего метода не идентичен классу поиска, или если у этого объекта поиска нет привилегий частного доступа, проверка доступа завершается неудачей.
Возвращаемый дескриптор метода будет иметь переменную арность только в том случае, если установлен модификатор переменной арности метода (0x0080)
(Примечание: внутренние методы JVM с именем "<init>" не видны для этой API, даже если инструкция invokespecial может ссылаться на них в особых случаях. Используйте findConstructor, чтобы безопасно получить доступ к методам инициализации экземпляров.)
Пример:
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... static class Listie extends ArrayList { public String toString() { return "[wee Listie]"; } static Lookup lookup() { return MethodHandles.lookup(); } } ... // no access to constructor via invokeSpecial: MethodHandle MH_newListie = Listie.lookup() .findConstructor(Listie.class, methodType(void.class)); Listie l = (Listie) MH_newListie.invokeExact(); try { assertEquals("impossible", Listie.lookup().findSpecial( Listie.class, "<init>", methodType(void.class), Listie.class)); } catch (NoSuchMethodException ex) { } // OK // access to super and self methods via invokeSpecial: MethodHandle MH_super = Listie.lookup().findSpecial( ArrayList.class, "toString" , methodType(String.class), Listie.class); MethodHandle MH_this = Listie.lookup().findSpecial( Listie.class, "toString" , methodType(String.class), Listie.class); MethodHandle MH_duper = Listie.lookup().findSpecial( Object.class, "toString" , methodType(String.class), Listie.class); assertEquals("[]", (String) MH_super.invokeExact(l)); assertEquals(""+l, (String) MH_this.invokeExact(l)); assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method try { assertEquals("inaccessible", Listie.lookup().findSpecial( String.class, "toString", methodType(String.class), Listie.class)); } catch (IllegalAccessException ex) { } // OK Listie subl = new Listie() { public String toString() { return "[subclass]"; } }; assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
- Параметры:
-
refc- класс или интерфейс, из которого осуществляется доступ к методу -
name- имя метода (которое не должно быть "<init>") -
type- тип метода, без аргумента получателя -
specialCaller- предполагаемый класс вызывающего метода для выполненияinvokespecial - Возвращает:
- желаемый дескриптор метода
- Изначает исключения:
-
NoSuchMethodException- если метод не существует -
IllegalAccessException- если проверка доступа завершается неудачей, или если метод являетсяstatic, или если модификатор переменной арности метода установлен, иasVarargsCollectorзавершается неудачей -
SecurityException- если менеджер безопасности присутствует и он отказывается предоставить доступ -
NullPointerException- если какой-либо аргумент равен null
findGetter
public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
- Параметры:
-
refc- класс или интерфейс, из которого осуществляется доступ к методу -
name- имя поля -
type- тип поля - Возвращает:
- дескриптор метода, который может загружать значения из поля
- Изначает исключения:
-
NoSuchFieldException- если поле не существует -
IllegalAccessException- если проверка доступа завершается неудачей, или если поле являетсяstatic -
SecurityException- если менеджер безопасности присутствует и он отказывается предоставить доступ -
NullPointerException- если какой-либо аргумент равен null - См. также:
findSetter
public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
- Параметры:
-
refc- класс или интерфейс, из которого осуществляется доступ к методу -
name- имя поля -
type- тип поля - Возвращает:
- дескриптор метода, который может сохранять значения в поле
- Изначает исключения:
-
NoSuchFieldException- если поле не существует -
IllegalAccessException- если проверка доступа завершается неудачей, или если поле являетсяstaticилиfinal -
SecurityException- если менеджер безопасности присутствует и он отказывается предоставить доступ -
NullPointerException- если какой-либо аргумент равен null - См. также:
findVarHandle
public VarHandle findVarHandle(Class<?> recv, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
name типа type, объявленному в классе типа recv. Тип переменной VarHandle — type, а тип координаты — recv.
Проверка доступа выполняется немедленно от имени класса поиска.
Определённые режимы доступа возвращаемого VarHandle недоступны в следующих условиях:
- если поле объявлено
final, режимы записи, атомарного обновления, атомарного обновления числовых значений и атомарного обновления битовых значений недоступны. - если тип поля отличается от
byte,short,char,int,long,float, илиdouble, то режимы атомарного обновления числовых значений недоступны. - если тип поля отличается от
boolean,byte,short,char,int, илиlong, то режимы атомарного обновления битовых значений недоступны.
Если поле объявлено volatile, возвращаемое VarHandle переопределит доступ к полю (в сущности, проигнорирует объявление volatile) в соответствии с его заданными режимами доступа.
Если тип поля — float или double, то режимы числового и атомарного обновления сравнивают значения, используя их битовое представление (см. Float.floatToRawIntBits(float) и Double.doubleToRawLongBits(double) соответственно).
- API Note:
- Битовое сравнение значений
floatили значенийdouble, выполняемое режимами числового и атомарного обновления, отличается от оператора==и методовFloat.equals(java.lang.Object)иDouble.equals(java.lang.Object), в частности в отношении сравнения значений NaN или сравнения-0.0с+0.0. Следует проявлять осторожность при выполнении операций сравнения и установки или сравнения и обмена с такими значениями, так как операция может неожиданно завершиться неудачей. Существует множество возможных значений NaN, которые считаютсяNaNв Java, хотя ни одна операция с плавающей запятой IEEE 754, предоставляемая Java, не может отличить их друг от друга. Ошибка выполнения может произойти, если ожидаемое или наблюдаемое значение является значением NaN и оно преобразуется (возможно, специфичным для платформы способом) в другое значение NaN, а значит, имеет другое битовое представление (см.Float.intBitsToFloat(int)илиDouble.longBitsToDouble(long)для получения более подробной информации). Значения-0.0и+0.0имеют разные битовые представления, но считаются равными при использовании оператора==. Ошибка выполнения может возникнуть, например, если числовой алгоритм вычислит ожидаемое значение, скажем,-0.0, и ранее вычислил наблюдаемое значение, скажем,+0.0. - Parameters:
-
recv- получающий класс, типаR, объявляющий нестатическое поле -
name- имя поля -
type- тип поля, типаT - Returns:
- VarHandle, предоставляющий доступ к нестатическим полям.
- Throws:
-
NoSuchFieldException- если поле не существует -
IllegalAccessException- если проверка доступа завершилась неудачей или если полеstatic -
SecurityException- если менеджер безопасности присутствует и он отклоняет доступ -
NullPointerException- если какой-либо аргумент имеет значение null - Since:
- 9
findStaticGetter
public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
При вызове возвращаемого обработчика методов класс поля будет инициализирован, если он ещё не был инициализирован.
- Parameters:
-
refc- класс или интерфейс, из которого доступ осуществляется к методу -
name- имя поля -
type- тип поля - Returns:
- обработчик методов, который может загружать значения из поля
- Throws:
-
NoSuchFieldException- если поле не существует -
IllegalAccessException- если проверка доступа завершилась неудачей или если поле неstatic -
SecurityException- если менеджер безопасности присутствует и он отклоняет доступ -
NullPointerException- если какой-либо аргумент имеет значение null
findStaticSetter
public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
При вызове возвращаемого обработчика методов класс поля будет инициализирован, если он ещё не был инициализирован.
- Parameters:
-
refc- класс или интерфейс, из которого доступ осуществляется к методу -
name- имя поля -
type- тип поля - Returns:
- обработчик методов, который может сохранять значения в поле
- Throws:
-
NoSuchFieldException- если поле не существует -
IllegalAccessException- если проверка доступа завершилась неудачей, или если поле неstaticилиfinal -
SecurityException- если менеджер безопасности присутствует и он отклоняет доступ -
NullPointerException- если какой-либо аргумент имеет значение null
findStaticVarHandle
public VarHandle findStaticVarHandle(Class<?> decl, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
name типа type в классе типа decl. Тип переменной VarHandle — type, и он не имеет типов координат. Проверка доступа выполняется немедленно от имени класса поиска.
Если на возвращаемом VarHandle выполняются операции, декларирующий класс будет инициализирован, если он ещё не был инициализирован.
Определённые режимы доступа возвращаемого VarHandle недоступны в следующих условиях:
- если поле объявлено
final, режимы записи, атомарного обновления, атомарного обновления числовых значений и атомарного обновления битовых значений недоступны. - если тип поля отличается от
byte,short,char,int,long,float, илиdouble, то режимы атомарного обновления числовых значений недоступны. - если тип поля отличается от
boolean,byte,short,char,int, илиlong, то режимы атомарного обновления битовых значений недоступны.
Если поле объявлено volatile, возвращаемое VarHandle переопределит доступ к полю (в сущности, проигнорирует объявление volatile) в соответствии с его заданными режимами доступа.
Если тип поля — float или double, то режимы числового и атомарного обновления сравнивают значения, используя их битовое представление (см. Float.floatToRawIntBits(float) и Double.doubleToRawLongBits(double) соответственно).
- API Note:
- Битовое сравнение значений
floatили значенийdouble, выполняемое режимами числового и атомарного обновления, отличается от оператора==и методовFloat.equals(java.lang.Object)иDouble.equals(java.lang.Object), в частности в отношении сравнения значений NaN или сравнения-0.0с+0.0. Следует проявлять осторожность при выполнении операций сравнения и установки или сравнения и обмена с такими значениями, так как операция может неожиданно завершиться неудачей. Существует множество возможных значений NaN, которые считаютсяNaNв Java, хотя ни одна операция с плавающей запятой IEEE 754, предоставляемая Java, не может отличить их друг от друга. Ошибка выполнения может произойти, если ожидаемое или наблюдаемое значение является значением NaN и оно преобразуется (возможно, специфичным для платформы способом) в другое значение NaN, а значит, имеет другое битовое представление (см.Float.intBitsToFloat(int)илиDouble.longBitsToDouble(long)для получения более подробной информации). Значения-0.0и+0.0имеют разные битовые представления, но считаются равными при использовании оператора==. Ошибка выполнения может возникнуть, например, если числовой алгоритм вычислит ожидаемое значение, скажем,-0.0, и ранее вычислил наблюдаемое значение, скажем,+0.0. - Parameters:
-
decl- класс, объявляющий статическое поле -
name- имя поля -
type- тип поля, типаT - Returns:
- VarHandle, предоставляющий доступ к статическому полю
- Throws:
-
NoSuchFieldException- если поле не существует -
IllegalAccessException- если проверка доступа завершилась неудачей, или если поле неstatic -
SecurityException- если менеджер безопасности присутствует и он отклоняет доступ -
NullPointerException- если какой-либо аргумент имеет значение null - Since:
- 9
bind
public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException
defc , в котором метод с заданным именем и типом доступен для класса поиска. Метод и все его типы аргументов должны быть доступны для объекта поиска. Тип обработчика метода будет таким же, как у метода, без добавления дополнительного параметра получателя. Заданный получатель будет привязан к обработчику метода, так что каждый вызов обработчика метода будет вызывать запрашиваемый метод для заданного получателя. Возвращаемый обработчик метода будет иметь переменную арность, если и только если бит модификатора переменной арности метода (0x0080) установлен и аргумент массива в конце не является единственным аргументом. (Если аргумент массива в конце является единственным аргументом, заданное значение получателя будет привязано к нему.)
Это почти эквивалентно следующему коду, с некоторыми различиями, отмеченными ниже:
гдеimport static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle mh0 = lookup().findVirtual(defc, name, type); MethodHandle mh1 = mh0.bindTo(receiver); mh1 = mh1.withVarargs(mh0.isVarargsCollector()); return mh1;
defc — это либо receiver.getClass() , либо супертип этого класса, в котором запрашиваемый метод доступен для класса поиска. (В отличие от bind, bindTo не сохраняет переменную арность. Кроме того, bindTo может выбросить ClassCastException в случаях, когда bind выбросил бы IllegalAccessException, как в случае, когда член является protected , а получатель ограничен findVirtual для класса поиска.)- Parameters:
-
receiver- объект, из которого обращаются к методу -
name- имя метода -
type- тип метода, без аргумента получателя - Returns:
- желаемый обработчик метода
- Throws:
-
NoSuchMethodException- если метод не существует -
IllegalAccessException- если проверка доступа не удалась или если бит модификатора переменной арности метода установлен, иasVarargsCollectorне удалась -
SecurityException- если менеджер безопасности присутствует и он отказывается предоставить доступ -
NullPointerException- если какой-либо аргумент равен null - See Also:
unreflect
public MethodHandle unreflect(Method m) throws IllegalAccessException
accessible метода не установлен, проверка доступа выполняется немедленно от имени класса поиска. Если m не общедоступный, не следует передавать полученный обработчик недоверенным сторонам. Возвращаемый обработчик метода будет иметь переменную арность, если и только если бит модификатора переменной арности метода (0x0080) установлен.
Если m статический, и если вызывается возвращаемый обработчик метода, класс метода будет инициализирован, если он ещё не был инициализирован.
- Parameters:
-
m- отражённый метод - Returns:
- обработчик метода, который может вызвать отражённый метод
- Throws:
-
IllegalAccessException- если проверка доступа не удалась или если бит модификатора переменной арности метода установлен, иasVarargsCollectorне удалась -
NullPointerException- если аргумент равен null
unreflectSpecial
public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException
invokespecial внутри явно указанного specialCaller. Тип обработчика метода будет таким же, как у метода, с предложенным типом получателя, соответствующим образом ограниченного. (Тип получателя будет specialCaller или подтип.) Если флаг accessible метода не установлен, проверка доступа выполняется немедленно от имени класса поиска, как если бы инструкция invokespecial связывалась. Перед разрешением метода, если явно указанный класс вызывающего не идентичен классу поиска, или если у этого объекта поиска нет привилегий частного доступа, доступ отказывается.
Возвращаемый обработчик метода будет иметь переменную арность, если и только если бит модификатора переменной арности метода (0x0080) установлен.
- Parameters:
-
m- отражённый метод -
specialCaller- класс, номинально вызывающий метод - Returns:
- обработчик метода, который может вызвать отражённый метод
- Throws:
-
IllegalAccessException- если проверка доступа не удалась, или если метод являетсяstatic, или если бит модификатора переменной арности метода установлен, иasVarargsCollectorне удалась -
NullPointerException- если какой-либо аргумент равен null
unreflectConstructor
public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException
newInstance, создавая новый экземпляр класса конструктора на аргументах, переданных обработчику метода. Если флаг accessible конструктора не установлен, проверка доступа выполняется немедленно от имени класса поиска.
Возвращаемый обработчик метода будет иметь переменную арность, если и только если бит модификатора переменной арности конструктора (0x0080) установлен.
Если вызывается возвращаемый обработчик метода, класс конструктора будет инициализирован, если он ещё не был инициализирован.
- Parameters:
-
c- отражённый конструктор - Returns:
- обработчик метода, который может вызвать отражённый конструктор
- Throws:
-
IllegalAccessException- если проверка доступа не удалась или если бит модификатора переменной арности метода установлен, иasVarargsCollectorне удалась -
NullPointerException- если аргумент равен null
unreflectGetter
public MethodHandle unreflectGetter(Field f) throws IllegalAccessException
static, обработчик метода не будет принимать аргументы. В противном случае его единственный аргумент будет экземпляром, содержащим поле. Если флаг Field объекта accessible не установлен, проверка доступа выполняется немедленно от имени класса поиска. Если поле статическое, и если вызывается возвращаемый обработчик метода, класс поля будет инициализирован, если он ещё не был инициализирован.
- Parameters:
-
f- отражённое поле - Returns:
- обработчик метода, который может загружать значения из отражённого поля
- Throws:
-
IllegalAccessException- если проверка доступа не удалась -
NullPointerException- если аргумент равен null
unreflectSetter
public MethodHandle unreflectSetter(Field f) throws IllegalAccessException
static, обработчик метода будет принимать один аргумент типа значения поля — значение, которое должно быть сохранено. В противном случае два аргумента будут — экземпляр, содержащий поле, и значение, которое должно быть сохранено. Если флаг Field объекта accessible не установлен, проверка доступа выполняется немедленно от имени класса поиска. Если поле является final, доступ для записи не будет разрешён, и проверка доступа не пройдёт, за исключением некоторых узких обстоятельств, документированных для Field.set. Обработчик метода возвращается только если соответствующий вызов метода Field объекта set мог вернуть нормальное значение. В частности, поля, которые являются одновременно static и final , никогда не могут быть установлены.
Если поле является static, и если вызывается возвращаемый обработчик метода, класс поля будет инициализирован, если он ещё не был инициализирован.
- Parameters:
-
f- отражённое поле - Returns:
- обработчик метода, который может сохранять значения в отражённое поле
- Throws:
-
IllegalAccessException- если проверка доступа не удалась или если поле являетсяfinalи доступ для записи не разрешён объектомField -
NullPointerException- если аргумент равен null
unreflectVarHandle
public VarHandle unreflectVarHandle(Field f) throws IllegalAccessException
f типа T, объявленному в классе типа R. Тип переменной VarHandle — T. Если поле не статическое, у VarHandle есть один тип координаты R. В противном случае поле статическое, и у VarHandle нет типов координат.
Проверка доступа выполняется немедленно от имени класса поиска, независимо от значения флага accessible поля.
Если поле статическое, а возвращённый VarHandle используется, класс, объявляющий поле, будет инициализирован, если он ещё не был инициализирован.
Некоторые режимы доступа возвращаемого VarHandle не поддерживаются в следующих условиях:
- если поле объявлено
final, то режимы записи, атомного обновления, атомного числового обновления и атомного побитового обновления не поддерживаются. - если тип поля отличается от
byte,short,char,int,long,floatилиdouble, то режимы атомного числового обновления не поддерживаются. - если тип поля отличается от
boolean,byte,short,char,intилиlong, то режимы атомного побитового обновления не поддерживаются.
Если поле объявлено volatile, возвращаемый VarHandle переопределит доступ к полю (эффективно проигнорирует объявление volatile) в соответствии с его указанными режимами доступа.
Если тип поля — float или double, то режимы числового и атомного обновления сравнивают значения, используя их двоичное представление (см. Float.floatToRawIntBits(float) и Double.doubleToRawLongBits(double) соответственно).
- API Note:
- Побитовое сравнение значений
floatилиdouble, выполняемое режимами числового и атомного обновления, отличается от оператора примитивного==и методовFloat.equals(java.lang.Object)иDouble.equals(java.lang.Object), особенно в отношении сравнения значений NaN или сравнения-0.0с+0.0. Следует проявлять осторожность при выполнении операции сравнения и установки или сравнения и обмена с такими значениями, так как операция может неожиданно завершиться неудачей. В Java существует множество возможных значений NaN, которые считаютсяNaNв Java, хотя ни одна операция с плавающей точкой IEEE 754, предоставляемая Java, не может их различить. Отказ от операции может произойти, если ожидаемое или наблюдаемое значение является значением NaN, и оно преобразуется (возможно, платформозависимым способом) в другое значение NaN и, следовательно, имеет другое двоичное представление (см.Float.intBitsToFloat(int)илиDouble.longBitsToDouble(long)для получения дополнительной информации). Значения-0.0и+0.0имеют разные двоичные представления, но считаются равными при использовании оператора примитива==. Отказ от операции может произойти, например, если числовой алгоритм вычисляет ожидаемое значение, скажем,-0.0, и ранее вычислил наблюдаемое значение, скажем,+0.0. - Параметры:
-
f- отражённое поле с типом поляTи классом объявления типаR - Возвращает:
- VarHandle, предоставляющий доступ к полям, не являющимся статическими, или к статическому полю
- Исключения:
-
IllegalAccessException- если проверка доступа завершается неудачей -
NullPointerException- если аргумент имеет значение null - С:
- 9
revealDirect
public MethodHandleInfo revealDirect(MethodHandle target)
target, созданный этим объектом поиска или аналогичным ему. Проверки безопасности и доступа гарантируют, что этот объект поиска способен воспроизвести целевой обработчик метода. Это означает, что раскрытие может завершиться неудачей, если целевой обработчик метода является прямым, но был создан объектом поиска, не связанным с ним. Это может произойти, если обработчик метода является зависимым от вызывающего объекта SecurityException и был создан объектом поиска для другого класса.- Параметры:
-
target- прямой обработчик метода для раскрытия в компоненты символической ссылки - Возвращает:
- символическая ссылка, которая может использоваться для восстановления этого обработчика метода из этого объекта поиска
- Исключения:
-
SecurityException- если менеджер безопасности присутствует и он отказывается предоставить доступ -
IllegalArgumentException- если целевой объект не является прямым обработчиком метода или если проверка доступа завершается неудачей -
NullPointerException- если целевой объект —null - С:
- 1.8
- См. также:
hasPrivateAccess
@Deprecated(since="14") public boolean hasPrivateAccess()
PRIVATE, который подразумевает полномочия доступа, но доступ MODULE с тех пор стал независимым от доступа PRIVATE. Рекомендуется вызывать hasFullPrivilegeAccess() вместо этого.true, если у этого объекта поиска есть доступ PRIVATE и MODULE. - Возвращает:
-
trueесли у этого объекта поиска есть доступPRIVATEиMODULE. - С:
- 9
hasFullPrivilegeAccess
public boolean hasFullPrivilegeAccess()
true, если у этого объекта поиска есть полный доступ с привилегиями, т.е. доступ PRIVATE и MODULE. Объект Lookup должен иметь полный доступ с привилегиями, чтобы получить доступ ко всем членам, разрешённым классу поиска lookup class.- Возвращает:
-
trueесли у этого объекта поиска есть полный доступ с привилегиями. - С:
- 14
- См. также:
© 1993, 2021, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html
PRIVATE, который подразумевает полный доступ к привилегиям, но доступMODULEс тех пор стал независимым от доступаPRIVATE.