Spec-Zone.ru › OpenJDK 21

Класс MethodHandles.Lookup

java.lang.Object
java.lang.invoke.MethodHandles.Lookup
Включающий класс:
MethodHandles
public static final class MethodHandles.Lookup extends Object
Объект lookup — это фабрика для создания обработчиков методов, когда для создания требуется проверка доступа. Обработчики методов не выполняют проверок доступа при вызове, а только при создании. Поэтому ограничения доступа к обработчику методов должны быть применены при его создании. Класс вызывающего, относительно которого применяются эти ограничения, известен как класс lookup.

Класс lookup, которому требуется создать обработчик метода, вызовет MethodHandles.lookup, чтобы создать фабрику для себя. При создании объекта фабрики Lookup идентификатор класса lookup определяется и безопасно сохраняется в объекте Lookup. Затем класс lookup (или его делегаты) могут использовать методы-фабрики в объекте Lookup для создания обработчиков методов для членов с проверкой доступа. Это включает все методы, конструкторы и поля, разрешенные классу lookup, даже закрытые.

Методы-фабрики Lookup

Методы-фабрики объекта Lookup соответствуют всем основным случаям использования методов, конструкторов и полей. Каждый обработчик метода, созданный методом-фабрикой, функционально эквивалентен определённому поведению байткода. (Поведения байткода описаны в разделе 5.4.3.5 спецификации виртуальной машины Java.) Вот сводка соответствия между методами-фабриками и поведением полученных обработчиков методов:
поведения методов lookup
выражение lookup член поведение байткода
lookup.findGetter(C.class,"f",FT.class) FT f; (T) this.f;
lookup.findStaticGetter(C.class,"f",FT.class) static
FT f;
(FT) C.f;
lookup.findSetter(C.class,"f",FT.class) FT f; this.f = x;
lookup.findStaticSetter(C.class,"f",FT.class) static
FT f;
C.f = arg;
lookup.findVirtual(C.class,"m",MT) T m(A*); (T) this.m(arg*);
lookup.findStatic(C.class,"m",MT) static
T m(A*);
(T) C.m(arg*);
lookup.findSpecial(C.class,"m",MT,this.class) T m(A*); (T) super.m(arg*);
lookup.findConstructor(C.class,MT) C(A*); new C(arg*);
lookup.unreflectGetter(aField) (static)?
FT f;
(FT) aField.get(thisOrNull);
lookup.unreflectSetter(aField) (static)?
FT f;
aField.set(thisOrNull, arg);
lookup.unreflect(aMethod) (static)?
T m(A*);
(T) aMethod.invoke(thisOrNull, arg*);
lookup.unreflectConstructor(aConstructor) C(A*); (C) aConstructor.newInstance(arg*);
lookup.unreflectSpecial(aMethod,this.class) T m(A*); (T) super.m(arg*);
lookup.findClass("C") class C { ... } C.class;
Здесь тип C — это класс или интерфейс, в котором ищется член, документированный как параметр с именем refc в методах lookup. Тип метода MT составлен из возвращаемого типа T и последовательности типов аргументов A*. Конструктор также имеет последовательность типов аргументов A* и считается возвращающим новый созданный объект типа C. И MT, и тип поля FT документированы как параметр с именем type. Формальный параметр this обозначает самоссылку типа C; если он присутствует, то всегда является ведущим аргументом для вызова обработчика метода. (В случае некоторых protected членов this может быть ограничен типом до класса lookup; см. ниже.) Наименование arg обозначает все остальные аргументы обработчика метода. В примерах кода для API ядра отражения имя thisOrNull обозначает нулевую ссылку, если доступный метод или поле статическое, и this в противном случае. Имена aMethod, aField, и aConstructor обозначают рефлективные объекты, соответствующие заданным членам, объявленным в типе C.

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

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

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

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

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

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

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

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

Поиск может завершиться ошибкой, потому что содержащий класс недоступен для класса lookup, или потому что необходимый член класса отсутствует, или потому что необходимый член класса недоступен для класса lookup, или потому что объект lookup недостаточно надёжен для доступа к члену. В случае функции установщика поля для поля final, принуждение к постоянству обрабатывается как своего рода контроль доступа, и поиск завершится ошибкой, за исключением специальных случаев Lookup.unreflectSetter. В любом из этих случаев метод ReflectiveOperationException будет выброшен во время попытки поиска. Точный класс будет одним из следующих:

  • NoSuchMethodException — если запрашивается метод, но его нет
  • NoSuchFieldException — если запрашивается поле, но его нет
  • IllegalAccessException — если член существует, но проверка доступа завершается неудачно

В общем случае, условия, при которых обработчик метода может быть получен с помощью lookup для метода M, не более жёсткие, чем условия, при которых класс lookup мог бы скомпилировать, проверить и разрешить вызов M. Там, где JVM могла бы вызвать исключения типа NoSuchMethodError, поиск обработчика метода, как правило, вызовет соответствующее проверяемое исключение, например NoSuchMethodException. И эффект вызова обработчика метода, полученного в результате поиска, точно эквивалентен выполнению скомпилированного, проверенного и разрешённого вызова M. Та же самая закономерность верна для полей и конструкторов.

Обсуждение: Проверки доступа применяются только к именованным и отражённым методам, конструкторам и полям. Другие методы создания обработчиков методов, такие как MethodHandle.asType, не требуют проверок доступа и используются независимо от любого объекта Lookup.

Если искомый член protected, применяются обычные правила JVM, включая требование, чтобы класс lookup находился в том же пакете, что и искомый член, или наследовал его. (См. спецификацию виртуальной машины Java, разделы 4.9.2, 5.4.3.5 и 6.4.) Кроме того, если искомый член — это нестатическое поле или метод в другом пакете, полученный обработчик метода может применяться только к объектам класса lookup или одного из его подклассов. Это требование выполняется за счёт сужения типа ведущего параметра this с C (который обязательно будет суперклассом класса lookup) до самого класса lookup.

JVM накладывает аналогичное требование на инструкцию invokespecial, что аргумент получателя должен соответствовать как разрешенному методу, так и текущему классу. Опять же, это требование обеспечивается сужением типа ведущего параметра до полученного дескриптора метода. (См. Спецификацию Java Virtual Machine, раздел 4.10.1.9.)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • безусловно экспортированные пакеты из M1
  • безусловно экспортированные пакеты из M0 если M1 считывает M0
  • безусловно экспортированные пакеты из третьего модуля M2 если M0 и M1 считывают M2
  • квалифицированно экспортированные пакеты из M1 в M0
  • квалифицированно экспортированные пакеты из M0 в M1 если M1 считывает M0
  • квалифицированно экспортированные пакеты из третьего модуля M2 в M0 и M1 если M0 и M1 считывают M2

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

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

Примечания:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Modifier and Type Class Description
static enum  MethodHandles.Lookup.ClassOption
Набор параметров класса, определяющих, добавляется ли скрытый класс, созданный методом Lookup::defineHiddenClass, динамически в качестве нового члена к вложению класса поиска, и/или имеет ли скрытый класс сильную связь с загрузчиком классов, помеченным как его определяющий загрузчик.

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

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

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

Modifier and Type Method Description
<T> Class<T> accessClass(Class<T> targetClass)
Определяет, может ли к классу быть предоставлен доступ из контекста поиска, определенного этим объектом Lookup.
MethodHandle bind(Object receiver, String name, MethodType type)
Создает метод-обработчик с ранней привязкой для нестатического метода.
Class<?> defineClass(byte[] bytes)
Создаёт и связывает класс или интерфейс из bytes, с тем же загрузчиком классов и в том же пакете выполнения и домене защиты, что и класс поиска этого поиска, как если бы вызывался ClassLoader::defineClass.
MethodHandles.Lookup defineHiddenClass(byte[] bytes, boolean initialize, MethodHandles.Lookup.ClassOption... options)
Создаёт скрытый класс или интерфейс из bytes, возвращая Lookup для нового созданного класса или интерфейса.
MethodHandles.Lookup defineHiddenClassWithClassData(byte[] bytes, Object classData, boolean initialize, MethodHandles.Lookup.ClassOption... options)
Создаёт скрытый класс или интерфейс из bytes с сопутствующими данными класса class data, возвращая Lookup для нового созданного класса или интерфейса.
MethodHandles.Lookup dropLookupMode(int modeToDrop)
Создаёт поиск в том же классе поиска, который этот объект поиска находит члены, но с режимом поиска, потерявшим данный режим поиска.
<T> Class<T> ensureInitialized(Class<T> targetClass)
Убеждается, что targetClass был инициализирован.
Class<?> findClass(String targetName)
Ищет класс по имени из контекста поиска, определённого этим объектом Lookup, как будто разрешён инструкцией ldc.
MethodHandle findConstructor(Class<?> refc, MethodType type)
Создаёт метод-обработчик, который создаёт объект и инициализирует его, используя конструктор указанного типа.
MethodHandle findGetter(Class<?> refc, String name, Class<?> type)
Создаёт метод-обработчик, предоставляющий доступ для чтения к нестатическому полю.
MethodHandle findSetter(Class<?> refc, String name, Class<?> type)
Создаёт метод-обработчик, предоставляющий доступ для записи к нестатическому полю.
MethodHandle findSpecial(Class<?> refc, String name, MethodType type, Class<?> specialCaller)
Создаёт метод-обработчик с ранней привязкой для виртуального метода.
MethodHandle findStatic(Class<?> refc, String name, MethodType type)
Создаёт метод-обработчик для статического метода.
MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type)
Создаёт метод-обработчик, предоставляющий доступ для чтения к статическому полю.
MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type)
Создаёт метод-обработчик, предоставляющий доступ для записи к статическому полю.
VarHandle findStaticVarHandle(Class<?> decl, String name, Class<?> type)
Создаёт VarHandle, предоставляющий доступ к статическому полю name типа type объявленному в классе типа decl.
VarHandle findVarHandle(Class<?> recv, String name, Class<?> type)
Создаёт VarHandle, предоставляющий доступ к нестатическому полю name типа type объявленному в классе типа recv.
MethodHandle findVirtual(Class<?> refc, String name, MethodType type)
Создаёт метод-обработчик для виртуального метода.
boolean hasFullPrivilegeAccess()
Возвращает true, если у этого поиска есть полный привилегированный доступ, т.е.
boolean hasPrivateAccess()
Устарело.
Этот метод первоначально был разработан для проверки доступа PRIVATE, который подразумевает полный привилегированный доступ, но доступ MODULE с тех пор стал независимым от доступа PRIVATE.
MethodHandles.Lookup in(Class<?> requestedLookupClass)
Создаёт поиск в указанном новом классе поиска.
Class<?> lookupClass()
Указывает, какой класс выполняет поиск.
int lookupModes()
Указывает, какие классы защиты доступа к членам может производить этот объект поиска.
Class<?> previousLookupClass()
Сообщает о классе поиска в другом модуле, из которого этот объект поиска был ранее телепортирован, или null.
MethodHandleInfo revealDirect(MethodHandle target)
Разбирает прямой метод-обработчик, созданный этим объектом поиска или аналогичным ему.
String toString()
Отображает имя класса, из которого должны выполняться поиски, за которым следует "/" и имя предыдущего класса поиска, если он есть.
MethodHandle unreflect(Method m)
Создаёт прямой метод-обработчик для m, если класс поиска имеет разрешение.
MethodHandle unreflectConstructor(Constructor<?> c)
Создаёт метод-обработчик для отражённого конструктора.
MethodHandle unreflectGetter(Field f)
Создаёт метод-обработчик, предоставляющий доступ для чтения к отражённому полю.
MethodHandle unreflectSetter(Field f)
Создаёт метод-обработчик, предоставляющий доступ для записи к отражённому полю.
MethodHandle unreflectSpecial(Method m, Class<?> specialCaller)
Создаёт метод-обработчик для отражённого метода.
VarHandle unreflectVarHandle(Field f)
Создаёт VarHandle, предоставляющий доступ к отражённому полю f типа T объявленному в классе типа R.

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

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

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

PUBLIC

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

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

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

PRIVATE

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

PROTECTED

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

PACKAGE

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

MODULE

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

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

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

БЕЗУСЛОВНЫЙ

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

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

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

ИСТОЧНИК

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

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

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

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

lookupClass

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

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

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

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

previousLookupClass

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

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

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

lookupModes

public int lookupModes()
Указывает, какие классы защиты доступа к членам может создавать этот объект поиска. Результат — битовая маска битов PUBLIC (0x01), PRIVATE (0x02), PROTECTED (0x04), PACKAGE (0x08), MODULE (0x10), UNCONDITIONAL (0x20) и ORIGINAL (0x40).

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

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

в

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

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

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

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

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

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

Параметры:
requestedLookupClass - желаемый класс поиска для нового объекта поиска
Возвращает:
объект поиска, который указывает на желаемый класс поиска, или тот же объект, если изменений нет
Изучает:
IllegalArgumentException - если requestedLookupClass — это примитивный тип или void или класс массива
NullPointerException - если аргумент равен null
См. также:
  • accessClass(Class)
  • Поиск между модулями

dropLookupMode

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

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

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

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

defineClass

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

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

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

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

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

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

defineHiddenClass

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

defineHiddenClassWithClassData

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

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

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

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

toString

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

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

Overrides:
toString в классе Object
Возвращает:
строковое представление объекта.
См. также:
  • in(java.lang.Class<?>)

findStatic

public MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException
Создаёт обработчик метода для статического метода. Тип обработчика метода будет таким же, как у метода. (Поскольку статические методы не принимают получателей, дополнительный аргумент получателя не вставляется в тип обработчика метода, как это было бы с findVirtual или findSpecial.) Метод и все его типы аргументов должны быть доступны объекту поиска.

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

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

Пример:

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle MH_asList = publicLookup().findStatic(Arrays.class,
  "asList", methodType(List.class, Object[].class));
assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
Параметры:
refc - класс, из которого осуществляется доступ к методу
name - имя метода
type - тип метода
Возвращает:
нужный обработчик метода
Исключения:
NoSuchMethodException - если метод не существует
IllegalAccessException - если проверка доступа не удалась, или если метод не static, или если бит переменной арности метода установлен, и asVarargsCollector не удалось
SecurityException - если менеджер безопасности присутствует и он отказывает в доступе
NullPointerException - если какой-либо аргумент имеет значение null

findVirtual

public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException
Создаёт обработчик метода для виртуального метода. Тип обработчика метода будет таким же, как у метода, с типом получателя (обычно refc) впереди. Метод и все его типы аргументов должны быть доступны объекту поиска.

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

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

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

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

Если класс является VarHandle, а строка имени соответствует имени метода режима доступа с полиморфизмом сигнатур, результирующий обработчик метода эквивалентен обработчику, созданному с помощью MethodHandles.varHandleInvoker(java.lang.invoke.VarHandle.AccessMode, java.lang.invoke.MethodType) с режимом доступа, соответствующим строке имени, и с теми же аргументами type.

Пример:

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle MH_concat = publicLookup().findVirtual(String.class,
  "concat", methodType(String.class, String.class));
MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class,
  "hashCode", methodType(int.class));
MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class,
  "hashCode", methodType(int.class));
assertEquals("xy", (String) MH_concat.invokeExact("x", "y"));
assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy"));
assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy"));
// interface method:
MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class,
  "subSequence", methodType(CharSequence.class, int.class, int.class));
assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString());
// constructor "internal method" must be accessed differently:
MethodType MT_newString = methodType(void.class); //()V for new String()
try { assertEquals("impossible", lookup()
        .findVirtual(String.class, "<init>", MT_newString));
 } catch (NoSuchMethodException ex) { } // OK
MethodHandle MH_newString = publicLookup()
  .findConstructor(String.class, MT_newString);
assertEquals("", (String) MH_newString.invokeExact());
Параметры:
refc - класс или интерфейс, из которого осуществляется доступ к методу
name - имя метода
type - тип метода, без аргумента получателя
Возвращает:
нужный обработчик метода
Исключения:
NoSuchMethodException - если метод не существует
IllegalAccessException - если проверка доступа не удалась, или если метод является static, или если бит переменной арности метода установлен, и asVarargsCollector не удалось
SecurityException - если менеджер безопасности присутствует и он отказывает в доступе
NullPointerException - если какой-либо аргумент имеет значение null

findConstructor

public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException
Создаёт обработчик метода, который создаёт объект и инициализирует его, используя конструктор указанного типа. Типы параметров обработчика метода будут такими же, как у конструктора, а тип возврата — ссылкой на класс конструктора. Конструктор и все его типы аргументов должны быть доступны объекту поиска.

Требуемый тип должен иметь тип возврата void. (Это согласуется с обработкой описателей типов конструкторов JVM.)

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

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

Пример:

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle MH_newArrayList = publicLookup().findConstructor(
  ArrayList.class, methodType(void.class, Collection.class));
Collection orig = Arrays.asList("x", "y");
Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig);
assert(orig != copy);
assertEquals(orig, copy);
// a variable-arity constructor:
MethodHandle MH_newProcessBuilder = publicLookup().findConstructor(
  ProcessBuilder.class, methodType(void.class, String[].class));
ProcessBuilder pb = (ProcessBuilder)
  MH_newProcessBuilder.invoke("x", "y", "z");
assertEquals("[x, y, z]", pb.command().toString());
Параметры:
refc - класс или интерфейс, из которого осуществляется доступ к методу
type - тип метода, без аргумента получателя, и типом возврата void
Возвращает:
нужный обработчик метода
Исключения:
NoSuchMethodException - если конструктор не существует
IllegalAccessException - если проверка доступа не удалась или если бит переменной арности метода установлен и asVarargsCollector не удалось
SecurityException - если менеджер безопасности присутствует и он отказывает в доступе
NullPointerException - если какой-либо аргумент имеет значение null

findClass

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

Для класса или интерфейса имя является бинарным именем. Для класса массива с n измерениями имя начинается с n вхождений '[' и продолжается типом элемента, закодированным в таблице, указанной в Class.getName().

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

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

ensureInitialized

public <T> Class<T> ensureInitialized(Class<T> targetClass) throws IllegalAccessException
Обеспечивает, что targetClass был инициализирован. Класс, который должен быть инициализирован, должен быть доступен для этого объекта Lookup. Этот метод вызывает инициализацию targetClass, если она ещё не была выполнена, как указано в JVMS 5.5.

Этот метод возвращает, когда targetClass полностью инициализирован или когда targetClass инициализируется текущей нитью.

Type Parameters:
T - тип класса, который должен быть инициализирован
Parameters:
targetClass - класс, который должен быть инициализирован
Returns:
targetClass , который был инициализирован или который инициализируется текущей нитью.
Throws:
IllegalArgumentException - если targetClass является примитивным типом или классом массива или массива
IllegalAccessException - если targetClass недоступен для этого поиска
ExceptionInInitializerError - если инициализация класса, вызванная этим методом, завершилась неудачей
SecurityException - если присутствует менеджер безопасности, и он отклоняет доступ
См. Спецификацию виртуальной машины Java:
5.5 Инициализация
С:
15

accessClass

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

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

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

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

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

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

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

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

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

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

Type Parameters:
T - тип класса, для которого проверяется доступ
Parameters:
targetClass - класс, для которого проверяется доступ
Returns:
targetClass , для которого проверка доступа была выполнена
Throws:
IllegalAccessException - если класс недоступен из класса поиска и предыдущего класса поиска (если он присутствует), используя разрешенные режимы доступа.
SecurityException - если присутствует менеджер безопасности, и он отклоняет доступ
NullPointerException - если targetClass является null
С:
9
См. также:
  • Переходные запросы между модулями

findSpecial

public MethodHandle findSpecial(Class<?> refc, String name, MethodType type, Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException
Создает обработчик метода с ранним связыванием для виртуального метода. Он пропустит проверки переопределенных методов на получателе, как если бы он был вызван из инструкции invokespecial внутри явно указанного specialCaller. Тип обработчика метода будет таким же, как у метода, с предварительно ограниченным типом получателя. (Тип получателя будет specialCaller или подтипом.) Метод и все его аргументы должны быть доступны объекту поиска.

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

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

(Примечание: внутренние методы JVM с именем "<init>" не видны этому API, даже если инструкция invokespecial может ссылаться на них в особых обстоятельствах. Используйте findConstructor, чтобы получить доступ к методам инициализации экземпляра безопасным способом.)

Пример:

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
static class Listie extends ArrayList {
  public String toString() { return "[wee Listie]"; }
  static Lookup lookup() { return MethodHandles.lookup(); }
}
...
// no access to constructor via invokeSpecial:
MethodHandle MH_newListie = Listie.lookup()
  .findConstructor(Listie.class, methodType(void.class));
Listie l = (Listie) MH_newListie.invokeExact();
try { assertEquals("impossible", Listie.lookup().findSpecial(
        Listie.class, "<init>", methodType(void.class), Listie.class));
 } catch (NoSuchMethodException ex) { } // OK
// access to super and self methods via invokeSpecial:
MethodHandle MH_super = Listie.lookup().findSpecial(
  ArrayList.class, "toString" , methodType(String.class), Listie.class);
MethodHandle MH_this = Listie.lookup().findSpecial(
  Listie.class, "toString" , methodType(String.class), Listie.class);
MethodHandle MH_duper = Listie.lookup().findSpecial(
  Object.class, "toString" , methodType(String.class), Listie.class);
assertEquals("[]", (String) MH_super.invokeExact(l));
assertEquals(""+l, (String) MH_this.invokeExact(l));
assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method
try { assertEquals("inaccessible", Listie.lookup().findSpecial(
        String.class, "toString", methodType(String.class), Listie.class));
 } catch (IllegalAccessException ex) { } // OK
Listie subl = new Listie() { public String toString() { return "[subclass]"; } };
assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
Parameters:
refc - класс или интерфейс, из которого осуществляется доступ к методу
name - имя метода (которое не должно быть "<init>")
type - тип метода, без аргумента получателя
specialCaller - предлагаемый вызывающий класс для выполнения invokespecial
Returns:
требуемый обработчик метода
Throws:
NoSuchMethodException - если метод не существует
IllegalAccessException - если проверка доступа завершилась неудачей, или если метод является static, или если бит переменной арности метода установлен, и asVarargsCollector завершился неудачей
SecurityException - если присутствует менеджер безопасности, и он отклоняет доступ
NullPointerException - если какой-либо аргумент равен null

findGetter

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

findSetter

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

findVarHandle

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

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

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

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

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

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

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

findStaticGetter

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

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

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

findStaticSetter

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

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

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

findStaticVarHandle

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

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

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

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

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

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

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

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

bind

public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException
Создаёт обработчик метода с ранней привязкой для нестатического метода. Получатель должен иметь супертип defc , в котором метод с заданным именем и типом доступен для класса поиска. Метод и все его типы аргументов должны быть доступны для объекта поиска. Тип обработчика метода будет таким же, как у метода, без добавления дополнительного параметра получателя. Указанный получатель будет привязан к обработчику метода, поэтому каждый вызов обработчика метода будет вызывать запрашиваемый метод для данного получателя.

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

Это почти эквивалентно следующему коду, с некоторыми различиями, указанными ниже:

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle mh0 = lookup().findVirtual(defc, name, type);
MethodHandle mh1 = mh0.bindTo(receiver);
mh1 = mh1.withVarargs(mh0.isVarargsCollector());
return mh1;
где defc это либо receiver.getClass() , или супертип этого класса, в котором запрашиваемый метод доступен для класса поиска. (В отличие от bind, bindTo не сохраняет переменную арность. Кроме того, bindTo может выбросить исключение ClassCastException в тех случаях, когда bind выбросил бы исключение IllegalAccessException, как в случае, когда член является protected , а получатель ограничен findVirtual классом поиска.)
Параметры:
receiver - объект, из которого осуществляется доступ к методу
name - имя метода
type - тип метода, с опущенным аргументом получателя
Возвращает:
необходимый обработчик метода
Исключения:
NoSuchMethodException - если метод не существует
IllegalAccessException - если проверка доступа завершается неудачно или если бит модификатора переменной арности метода установлен, и asVarargsCollector завершается неудачно
SecurityException - если менеджер безопасности присутствует и он отказывается предоставить доступ
NullPointerException - если любой аргумент равен null
См. также:
  • MethodHandle.bindTo(java.lang.Object)
  • findVirtual(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType)

unreflect

public MethodHandle unreflect(Method m) throws IllegalAccessException
Создаёт прямой обработчик метода для m, если класс поиска имеет разрешение. Если m не статический, аргумент получателя обрабатывается как начальный аргумент. Если m виртуальный, переопределение соблюдается при каждом вызове. В отличие от API ядра рефлексии, исключения не обертываются. Тип обработчика метода будет таким же, как у метода, с добавленным типом получателя (но только если он не статический). Если флаг accessible метода не установлен, проверка доступа выполняется немедленно от имени класса поиска. Если m не является общедоступным, не следует передавать полученный обработчик недоверенным сторонам.

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

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

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

unreflectSpecial

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

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

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

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

unreflectConstructor

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

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

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

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

Параметры:
c - отражённый конструктор
Возвращает:
обработчик метода, который может вызвать отражённый конструктор
Исключения:
IllegalAccessException - если проверка доступа завершается неудачно или если бит модификатора переменной арности метода установлен, и asVarargsCollector завершается неудачно
NullPointerException - если аргумент равен null

unreflectGetter

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

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

Параметры:
f - отражённое поле
Возвращает:
обработчик метода, который может загружать значения из отражённого поля
Исключения:
IllegalAccessException - если проверка доступа завершается неудачно
NullPointerException - если аргумент равен null

unreflectSetter

public MethodHandle unreflectSetter(Field f) throws IllegalAccessException
Создаёт обработчик метода для записи в отражённое поле. Тип обработчика метода будет иметь тип void в качестве типа возвращаемого значения. Если поле является 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
Создаёт VarHandle, предоставляющий доступ к отражённому полю f типа T объявленному в классе типа R. Тип переменной VarHandle — T. Если поле не статическое, VarHandle имеет один тип координаты — R. В противном случае поле статическое, и у VarHandle нет типов координат.

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

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

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

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

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

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

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

revealDirect

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

hasPrivateAccess

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

hasFullPrivilegeAccess

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

© 1993, 2023, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html

Spec-Zone.ru

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