Класс 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 FooClassCastException):(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), определяется следующим образом: - Если все интерфейсы прокси находятся в экспортируемых или открытых пакетах:
- если все интерфейсы прокси являются public, класс прокси будет public и находиться в безусловно экспортируемом, но не открытом пакете. Имя пакета и модуля не определено.
- если хотя бы один из интерфейсов прокси является non-public, класс прокси будет non-public и находиться в пакете и модуле интерфейсов, не являющихся public. Все интерфейсы, не являющиеся public, должны находиться в одном пакете и модуле; в противном случае проксирование невозможно.
- Если хотя бы один интерфейс прокси находится в пакете, который является неэкспортируемым и неоткрытым:
- если все интерфейсы прокси являются public, класс прокси будет public и находиться в неэкспортируемом, неоткрытом пакете динамического модуля. Имена пакета и модуля не определены.
- если хотя бы один из интерфейсов прокси является 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
- См. также:
Краткое описание полей
| Модификатор и тип | Поле | Описание |
|---|---|---|
protected InvocationHandler |
h |
обработчик вызова для этого экземпляра прокси. |
Краткое описание конструкторов
| Модификатор | Конструктор | Описание |
|---|---|---|
protected |
Создаёт новый экземпляр Proxy из подкласса (обычно динамического класса прокси) с указанным значением обработчика вызова. |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
static InvocationHandler |
getInvocationHandler |
Возвращает обработчик вызова для указанного экземпляра прокси. |
static Class |
getProxyClass |
Устарело. Классы прокси, сгенерированные в именованном модуле, инкапсулированы и недоступны коду за пределами этого модуля. |
static boolean |
isProxyClass |
Возвращает true, если заданный класс является классом прокси. |
static Object |
newProxyInstance |
Возвращает экземпляр прокси для указанных интерфейсов, передающий вызовы методов указанному обработчику вызова. |
Подробное описание полей
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)
- Примечание по реализации:
- Надёжность этого метода важна для его использования при принятии решений о безопасности, поэтому его реализация не должна просто проверять, наследуется ли рассматриваемый класс от
Proxy. - Параметры:
-
cl— класс для проверки - Возвращает:
-
true, если класс является классом прокси, иfalseв противном случае - Выбрасывает:
-
NullPointerException— еслиclявляетсяnull
getInvocationHandler
public static InvocationHandler getInvocationHandler(Object proxy) throws IllegalArgumentException
- Параметры:
-
proxy— экземпляр прокси, для которого нужно вернуть обработчик вызова - Возвращает:
- обработчик вызова для экземпляра прокси
- Выбрасывает:
-
IllegalArgumentException— если аргумент не является экземпляром прокси -
NullPointerException— еслиproxyявляетсяnull
© 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