Spec-Zone.ru › OpenJDK 24

Класс 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, lookup все равно может иметь успех, даже если нет эквивалентного выражения Java или константы байткода.
  • Аналогично, если T или MT не доступен символично из загрузчика класса lookup, lookup все равно может иметь успех. Например, lookup для MethodHandle.invokeExact и MethodHandle.invoke всегда будут успешными, независимо от запрошенного типа.
  • Если искомый метод имеет очень большую арность, создание обработчика метода может завершиться неудачей с исключением IllegalArgumentException из-за того, что тип обработчика метода имеет слишком много параметров.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Таблица ниже показывает режимы доступа Lookup, созданного любым из следующих фабричных или преобразовательных методов:
  • 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() У
PUB.in(D) в другом модуле У
PUB.in(D).in(E) третий модуль У
PUB.dropLookupMode(UNCONDITIONAL) нет
privateLookupIn(C1,PUB) неудачно IAE
ANY.in(X), для недоступного X нет

Примечания:

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

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

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

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

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

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

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

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

С:
1.7

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

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

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

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

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

Modifier and Type Method Описание
<T> Class<T> accessClass(Class<T> targetClass)
Определяет, доступен ли класс из контекста поиска, определенного этим объектом Lookup.
MethodHandle bind(Object receiver, String name, MethodType type)
Создает обработчик метода со связыванием во время выполнения для нестатического метода.
Class<?> defineClass(byte[] bytes)
Создает и связывает класс или интерфейс из bytes с тем же загрузчиком классов и в том же пакете времени выполнения и областью защиты, что и класс поиска lookup class, как при вызове 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 с связанными данными класса, возвращая 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 модификатора.

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

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

PRIVATE

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

PROTECTED

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

PACKAGE

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

MODULE

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

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

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

БЕЗУСЛОВНЫЙ

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

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

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

ИСТОЧНИК

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

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

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

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

lookupClass

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

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

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

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

previousLookupClass

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

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

Возвращает:
класс поиска в другом модуле, из которого этот объект поиска был ранее перенесен, или null
С:
14
См. также:
  • 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)

in

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

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

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

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

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

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

Parameters:
requestedLookupClass - желаемый класс поиска для нового объекта поиска
Returns:
объект поиска, который указывает на желаемый класс поиска, или тот же объект, если изменений нет
Throws:
IllegalArgumentException - если requestedLookupClass является примитивным типом, void или классом массива
NullPointerException - если аргумент равен null
See Also:
  • 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 Note:
Поиск с режимом PACKAGE, но без режима PRIVATE, может безопасно делегировать доступ к непубличным членам в пакете класса поиска, не предоставляя приватный доступ. Поиск с режимом MODULE, но без режима PACKAGE, может безопасно делегировать PUBLIC доступ в модуле класса поиска, не предоставляя доступ к пакету. Поиск с предыдущим классом поиска (и режимом PUBLIC, но без режима MODULE) может безопасно делегировать доступ к публичным классам, доступным как для модуля класса поиска, так и для модуля предыдущего класса поиска.
Parameters:
modeToDrop - режим поиска для удаления
Returns:
объект поиска, у которого отсутствует указанный режим, или тот же объект, если изменений нет
Throws:
IllegalArgumentException - если modeToDrop не является одним из PUBLIC, MODULE, PACKAGE, PROTECTED, PRIVATE, ORIGINAL или UNCONDITIONAL
Since:
9
See Also:
  • MethodHandles.privateLookupIn(java.lang.Class<?>, java.lang.invoke.MethodHandles.Lookup)

defineClass

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

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

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

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

Parameters:
bytes - байты класса
Returns:
объект Class для класса
Throws:
IllegalAccessException - если у этого поиска нет доступа PACKAGE
ClassFormatError - если bytes не является структурой ClassFile
IllegalArgumentException - если bytes обозначает класс в другом пакете, чем класс поиска, или bytes не является классом или интерфейсом (ACC_MODULE флаг установлен в значении элемента access_flags)
VerifyError - если созданный класс не может быть проверен
LinkageError - если созданный класс не может быть связан по любой другой причине
NullPointerException - если bytes равен null
Since:
9
See Also:
  • 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 modes) для данного 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 считается имеющим ту же средовую упаковку, модуль и область защиты, что и класс-объект поиска данного Lookup.
    • Пусть GN — бинарное имя, полученное путём взятия N (бинарное имя, закодированное во внутреннем формате) и замены ASCII косых черт на ASCII точки. Для экземпляра Class, представляющего C:
      • Class.getName() возвращает строку GN + "/" + <suffix>, хотя это не является допустимым бинарным именем класса или интерфейса.
      • Class.descriptorString() возвращает строку "L" + N + "." + <suffix> + ";", хотя это не является допустимым именем описателя типа.
      • Class.describeConstable() возвращает пустой необязательный параметр, так как C не может быть описан в номинальной форме.

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

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

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

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

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

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

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

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

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

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

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

Переопределяет:
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 завершился неудачно
NullPointerException - если любой аргумент равен null

findVirtual

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

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

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

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

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

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

Пример:

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

findConstructor

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

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

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

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

Пример:

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

findClass

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

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

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

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

ensureInitialized

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

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

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

accessClass

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

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

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

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

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

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

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

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

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

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

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

findSpecial

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

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

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

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

Пример:

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

findGetter

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

findStaticGetter

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

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

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

findStaticSetter

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

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

Параметры:
refc - класс или интерфейс, из которого осуществляется доступ к методу
name - имя поля
type - тип поля
Возвращает:
обработчик методов, который может сохранять значения в поле
Выбрасывает:
NoSuchFieldException - если поле не существует
IllegalAccessException - если проверка доступа завершается неудачей или если поле не является static или является final
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
NullPointerException - если любой аргумент равен null
С:
9

связывать

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

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

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

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

отразить

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

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

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

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

отразить специальный

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

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

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

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

отразить конструктор

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

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

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

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

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

отразить геттер

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

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

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

отразить сеттер

public MethodHandle unreflectSetter(Field f) throws IllegalAccessException
Создаёт обработчик метода, предоставляющий доступ для записи к отражённому полю. Тип обработчика метода будет иметь тип 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 - прямое обращение к методу, которое нужно раскрыть до символьных компонентов ссылки
Возвращает:
символьная ссылка, которая может быть использована для реконструкции этого обработчика метода из этого объекта поиска
Исключения:
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, 2025, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://download.java.net/java/early_access/jdk24/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html

Spec-Zone.ru

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