Spec-Zone.ru › OpenJDK 25

Класс Proxy

java.lang.Object
java.lang.reflect.Proxy
Все реализуемые интерфейсы:
Serializable
public class Proxy extends Object implements Serializable
Proxy предоставляет статические методы для создания объектов, которые действуют как экземпляры интерфейсов, но позволяют настраивать вызов методов. Чтобы создать экземпляр прокси для некоторого интерфейса Foo:
    InvocationHandler handler = new MyInvocationHandler(...);
    Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                         new Class<?>[] { Foo.class },
                                         handler);

Класс прокси — это класс, создаваемый во время выполнения, который реализует указанный список интерфейсов, называемых интерфейсами прокси. Экземпляр прокси — это экземпляр класса прокси. С каждым экземпляром прокси связан объект обработчика вызова, реализующий интерфейс InvocationHandler. Вызов метода экземпляра прокси через один из его интерфейсов прокси передаётся методу invoke обработчика вызова этого экземпляра с передачей экземпляра прокси, объекта java.lang.reflect.Method, идентифицирующего вызванный метод, и массива типа Object, содержащего аргументы. Обработчик вызова обрабатывает закодированный вызов метода соответствующим образом, а возвращаемое им значение становится результатом вызова метода экземпляра прокси.

Класс прокси обладает следующими свойствами:

  • Полное имя класса прокси не определено. Однако пространство имён классов, начинающихся со строки "$Proxy", зарезервировано для классов прокси.
  • Пакет и модуль, в которых определяется класс прокси, указаны ниже.
  • Класс прокси является final и non-abstract.
  • Класс прокси наследуется от java.lang.reflect.Proxy.
  • Класс прокси реализует в точности интерфейсы, указанные при его создании, в том же порядке. Вызов getInterfaces для его объекта Class вернёт массив, содержащий тот же список интерфейсов (в порядке, указанном при создании); вызов getMethods для его объекта Class вернёт массив объектов Method, включающий все методы этих интерфейсов; а вызов getMethod обнаружит методы в интерфейсах прокси ожидаемым образом.
  • ProtectionDomain класса прокси совпадает с таковым у системных классов, загруженных загрузчиком классов начального уровня, например java.lang.Object.
  • Метод Proxy.isProxyClass можно использовать, чтобы определить, является ли заданный класс классом прокси.

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

  • Для экземпляра прокси proxy и одного из интерфейсов Foo, реализуемых его классом прокси, следующее выражение вернёт true:
        proxy instanceof Foo
    
    ; следующая операция приведения типа завершится успешно (не вызвав ClassCastException):
        (Foo) proxy
    
  • С каждым экземпляром прокси связан обработчик вызова, переданный его конструктору. Статический метод Proxy.getInvocationHandler вернёт обработчик вызова, связанный с переданным ему в качестве аргумента экземпляром прокси.
  • Вызов метода интерфейса для экземпляра прокси будет закодирован и передан методу invoke обработчика вызова, как описано в документации этого метода.
  • Интерфейс прокси может определять метод по умолчанию или прямо либо косвенно наследовать метод по умолчанию от своего суперинтерфейса. Обработчик вызова может вызвать метод по умолчанию интерфейса прокси, вызвав InvocationHandler::invokeDefault.
  • Вызов методов hashCode, equals или toString, объявленных в java.lang.Object, для экземпляра прокси будет закодирован и передан методу invoke обработчика вызова так же, как кодируются и передаются вызовы методов интерфейса, как описано выше. Объявляющим классом объекта Method, переданного в invoke, будет java.lang.Object. Остальные открытые методы экземпляра прокси, унаследованные от java.lang.Object, не переопределяются классом прокси, поэтому вызовы этих методов ведут себя так же, как и для экземпляров java.lang.Object.

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

Пакет и модуль, к которым принадлежит класс прокси, выбираются так, чтобы доступность класса прокси соответствовала доступности интерфейсов прокси. В частности, принадлежность к пакету и модулю класса прокси, определённого с помощью методов getProxyClass(ClassLoader, Class[]) или newProxyInstance(ClassLoader, Class[], InvocationHandler), определяется следующим образом:
  1. Если все интерфейсы прокси находятся в экспортируемых или открытых пакетах:
    1. если все интерфейсы прокси являются public, класс прокси будет public и находиться в безусловно экспортируемом, но не открытом пакете. Имя пакета и модуля не определено.
    2. если хотя бы один из интерфейсов прокси является non-public, класс прокси будет non-public и находиться в пакете и модуле интерфейсов, не являющихся public. Все интерфейсы, не являющиеся public, должны находиться в одном пакете и модуле; в противном случае проксирование невозможно.
  2. Если хотя бы один интерфейс прокси находится в пакете, который является неэкспортируемым и неоткрытым:
    1. если все интерфейсы прокси являются public, класс прокси будет public и находиться в неэкспортируемом, неоткрытом пакете динамического модуля. Имена пакета и модуля не определены.
    2. если хотя бы один из интерфейсов прокси является non-public, класс прокси будет non-public и находиться в пакете и модуле интерфейсов, не являющихся public. Все интерфейсы, не являющиеся public, должны находиться в одном пакете и модуле; в противном случае проксирование невозможно.

Обратите внимание: если один экземпляр прокси реализует интерфейсы с разными уровнями доступа — например, экспортируемый открытый интерфейс и неэкспортируемый интерфейс, не являющийся public, — доступность класса прокси определяется наименее доступным интерфейсом прокси.

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

В этой спецификации термин «неэкспортируемый пакет» означает пакет, не экспортируемый для всех модулей, а термин «неоткрытый пакет» — пакет, не открытый для всех модулей. В частности, эти термины относятся к пакету, который либо не экспортируется/не открыт содержащим его модулем, либо экспортируется/открывается этим модулем ограниченным образом.

Динамические модули

Динамический модуль — это именованный модуль, создаваемый во время выполнения. Класс прокси, определённый в динамическом модуле, инкапсулирован и недоступен ни одному модулю. Вызов Constructor.newInstance(Object...) для класса прокси в динамическом модуле вызовет IllegalAccessException; вместо него следует использовать метод Proxy.newProxyInstance.

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

Методы, дублирующиеся в нескольких интерфейсах прокси

Если два или более интерфейса прокси содержат метод с одинаковым именем и сигнатурой параметров, порядок интерфейсов класса прокси приобретает значение. Когда такой дублирующийся метод вызывается для экземпляра прокси, объект Method, передаваемый обработчику вызова, не обязательно будет тем объектом, объявляющий класс которого является супертипом типа ссылки интерфейса, через который был вызван метод прокси. Это ограничение существует потому, что соответствующая реализация метода в сгенерированном классе прокси не может определить, через какой интерфейс она была вызвана. Поэтому, когда дублирующийся метод вызывается для экземпляра прокси, объект Method для метода из первого интерфейса в списке интерфейсов класса прокси, содержащего этот метод (непосредственно или унаследованного через суперинтерфейс), передаётся методу invoke обработчика вызова независимо от типа ссылки, через которую был выполнен вызов метода.

Если интерфейс прокси содержит метод с тем же именем и сигнатурой параметров, что и методы hashCode, equals или toString класса java.lang.Object, при вызове такого метода для экземпляра прокси объект Method, передаваемый обработчику вызова, будет иметь java.lang.Object в качестве объявляющего класса. Иными словами, открытые нефинальные методы java.lang.Object логически предшествуют всем интерфейсам прокси при определении того, какой объект Method передать обработчику вызова.

Также обратите внимание: когда дублирующийся метод передаётся обработчику вызова, метод invoke может выбрасывать только проверяемые исключения, типы которых являются подтипами одного из типов исключений в предложении throws метода во всех интерфейсах прокси, через которые он может быть вызван. Если метод invoke выбрасывает проверяемое исключение, не являющееся подтипом ни одного из типов исключений, объявленных методом в одном из интерфейсов прокси, через которые он может быть вызван, вызов метода экземпляра прокси приведёт к выбросу непроверяемого UndeclaredThrowableException. Это ограничение означает, что не все типы исключений, возвращаемые при вызове getExceptionTypes для объекта Method, переданного методу invoke, обязательно можно успешно выбросить из метода invoke.

С момента появления:
1.3
См. также:
  • InvocationHandler
  • Сериализованная форма

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

Модификатор и тип Поле Описание
protected InvocationHandler h
обработчик вызова для этого экземпляра прокси.

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

Proxy(InvocationHandler h)
Модификатор Конструктор Описание
protected
Создаёт новый экземпляр Proxy из подкласса (обычно динамического класса прокси) с указанным значением обработчика вызова.

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

Модификатор и тип Метод Описание
static InvocationHandler getInvocationHandler(Object proxy)
Возвращает обработчик вызова для указанного экземпляра прокси.
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)
Устарело.
Классы прокси, сгенерированные в именованном модуле, инкапсулированы и недоступны коду за пределами этого модуля.
static boolean isProxyClass(Class<?> cl)
Возвращает true, если заданный класс является классом прокси.
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
Возвращает экземпляр прокси для указанных интерфейсов, передающий вызовы методов указанному обработчику вызова.

Методы, объявленные в классе Object

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

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

h

protected InvocationHandler h
обработчик вызова для этого экземпляра прокси.

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

Proxy

protected Proxy(InvocationHandler h)
Создаёт новый экземпляр Proxy из подкласса (обычно динамического класса прокси) с указанным значением обработчика вызова.
Параметры:
h — обработчик вызова для этого экземпляра прокси
Выбрасывает:
NullPointerException — если заданный обработчик вызова, h, является null.

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

getProxyClass

@Deprecated public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException
Устарело.
Классы прокси, сгенерированные в именованном модуле, инкапсулированы и недоступны коду за пределами этого модуля. Вызов Constructor.newInstance для недоступного класса прокси приведёт к IllegalAccessException. Вместо этого используйте newProxyInstance(ClassLoader, Class[], InvocationHandler) для создания экземпляра прокси.
Возвращает объект java.lang.Class класса прокси по загрузчику классов и массиву интерфейсов. Класс прокси будет определён указанным загрузчиком классов и будет реализовывать все предоставленные интерфейсы. Если хотя бы один из заданных интерфейсов не является public, класс прокси также не будет public. Если загрузчик классов уже определил класс прокси для такой же перестановки интерфейсов, будет возвращён существующий класс прокси; в противном случае класс прокси для этих интерфейсов будет динамически сгенерирован и определён загрузчиком классов.
Параметры:
loader — загрузчик классов, в котором определяется класс прокси
interfaces — список интерфейсов, которые должен реализовывать класс прокси
Возвращает:
класс прокси, определённый в указанном загрузчике классов и реализующий указанные интерфейсы
Выбрасывает:
IllegalArgumentException — если нарушено какое-либо из ограничений на параметры
NullPointerException — если аргумент массива interfaces или любой из его элементов является null
См. также:
  • Принадлежность класса прокси к пакету и модулю

newProxyInstance

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
Возвращает экземпляр прокси для указанных интерфейсов, передающий вызовы методов указанному обработчику вызова.

Если нарушено какое-либо из следующих ограничений, будет выброшено IllegalArgumentException:

  • Все объекты Class в заданном массиве interfaces должны представлять не скрытые и не запечатанные интерфейсы, а не классы или примитивные типы.
  • Никакие два элемента массива interfaces не должны ссылаться на идентичные объекты Class.
  • Все типы интерфейсов должны быть доступны по имени через указанный загрузчик классов. Другими словами, для загрузчика классов cl и каждого интерфейса i должно выполняться следующее выражение:

    Class.forName(i.getName(), false, cl) == i

  • Все типы, на которые ссылаются сигнатуры всех открытых методов указанных интерфейсов и их суперинтерфейсов, должны быть доступны по имени через указанный загрузчик классов.
  • Все интерфейсы, не являющиеся public, должны находиться в одном пакете и модуле, определённом указанным загрузчиком классов, а модуль интерфейсов, не являющихся public, должен иметь доступ ко всем типам интерфейсов; иначе класс прокси не сможет реализовать все интерфейсы независимо от пакета, в котором он определён.
  • Для любого набора методов-членов указанных интерфейсов с одинаковой сигнатурой:
    • Если тип возвращаемого значения любого из методов является примитивным типом или void, все методы должны иметь тот же тип возвращаемого значения.
    • В противном случае один из методов должен иметь тип возвращаемого значения, совместимый со всеми типами возвращаемых значений остальных методов.
  • Создаваемый класс прокси не должен превышать ограничения, накладываемые виртуальной машиной на классы. Например, ВМ может ограничить число интерфейсов, которые может реализовывать класс, значением 65535; в этом случае размер массива interfaces не должен превышать 65535.

Обратите внимание: порядок указанных интерфейсов прокси имеет значение: два запроса на создание класса прокси с одинаковым набором интерфейсов, но в разном порядке приведут к созданию двух разных классов прокси.

Параметры:
loader — загрузчик классов, в котором определяется класс прокси
interfaces — список интерфейсов, которые должен реализовывать класс прокси
h — обработчик вызова, которому передаются вызовы методов
Возвращает:
экземпляр прокси с указанным обработчиком вызова, принадлежащий классу прокси, определённому указанным загрузчиком классов и реализующему указанные интерфейсы
Выбрасывает:
IllegalArgumentException — если нарушено какое-либо из ограничений на параметры
NullPointerException — если аргумент массива interfaces или любой из его элементов является null либо если обработчик вызова, h, является null
См. также:
  • Принадлежность класса прокси к пакету и модулю

isProxyClass

public static boolean isProxyClass(Class<?> cl)
Возвращает true, если заданный класс является классом прокси.
Примечание по реализации:
Надёжность этого метода важна для его использования при принятии решений о безопасности, поэтому его реализация не должна просто проверять, наследуется ли рассматриваемый класс от Proxy.
Параметры:
cl — класс для проверки
Возвращает:
true, если класс является классом прокси, и false в противном случае
Выбрасывает:
NullPointerException — если cl является null

getInvocationHandler

public static InvocationHandler getInvocationHandler(Object proxy) throws IllegalArgumentException
Возвращает обработчик вызова для указанного экземпляра прокси.
Параметры:
proxy — экземпляр прокси, для которого нужно вернуть обработчик вызова
Возвращает:
обработчик вызова для экземпляра прокси
Выбрасывает:
IllegalArgumentException — если аргумент не является экземпляром прокси
NullPointerException — если proxy является null

Сообщить об ошибке или предложить улучшение
Дополнительные справочные материалы по API и документацию для разработчиков см. в разделе Документация Java SE, содержащем более подробные описания для разработчиков, концептуальные обзоры, определения терминов, обходные решения и примеры работающего кода. Другие версии.
Java является товарным знаком или зарегистрированным товарным знаком Oracle и/или её аффилированных лиц в США и других странах.
Авторское право © 1993, 2025, Oracle и/или её аффилированные лица, 500 Oracle Parkway, Redwood Shores, CA 94065 USA.
Все права защищены. Использование регулируется условиями лицензии и политикой распространения документации.

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

Spec-Zone.ru

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