Класс 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 и не абстрактным.
- Класс-прокси расширяет
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), определяется следующим образом: - Если все прокси-интерфейсы находятся в экспортированных или открытых пакетах:
- если все прокси-интерфейсы являются публичными, то класс-прокси является публичным в безусловно экспортированном, но не открытом пакете. Имя пакета и модуля не определены.
- если хотя бы один из всех прокси-интерфейсов является непубличным, то класс-прокси является непубличным в пакете и модуле непубличных интерфейсов. Все непубличные интерфейсы должны находиться в одном пакете и модуле; в противном случае их проксирование невозможно.
- Если хотя бы один прокси-интерфейс находится в пакете, который является неэкспортированным и неокрытым:
- если все прокси-интерфейсы являются публичными, то класс-прокси является публичным в неэкспортированном, неокрытом пакете динамического модуля. Имена пакета и модуля не определены.
- если хотя бы один из всех прокси-интерфейсов является непубличным, то класс-прокси является непубличным в пакете и модуле непубличных интерфейсов. Все непубличные интерфейсы должны находиться в одном пакете и модуле; в противном случае их проксирование невозможно.
Обратите внимание, что если прокси-интерфейсы с различной доступностью — например, экспортированный публичный интерфейс и неэкспортированный непубличный интерфейс — проксируются одним экземпляром, то доступность класса-прокси регулируется наименее доступным прокси-интерфейсом.
Обратите внимание, что произвольный код может получить доступ к классу-прокси в открытом пакете с помощью setAccessible, в то время как класс-прокси в неокрытом пакете никогда не доступен коду за пределами модуля класса-прокси.
В этом спецификации «неэкспортированный пакет» относится к пакету, который не экспортируется во все модули, а «неокрытый пакет» — к пакету, который не открыт для всех модулей. В частности, эти термины относятся к пакету, который либо не экспортирован/открыт содержащим его модулем, либо экспортирован/открыт в квалифицированном виде содержащим его модулем.
Динамические модули
Динамический модуль — это именованный модуль, генерируемый во время выполнения. Класс-прокси, определённый в динамическом модуле, является изолированным и недоступным для других модулей. Вызов Constructor.newInstance(Object...) на классе-прокси в динамическом модуле вызовет IllegalAccessException; вместо этого следует использовать метод Proxy.newProxyInstance.
Динамический модуль может считывать модули всех суперинтерфейсов класса-прокси и модули классов и интерфейсов, на которые ссылаются все общедоступные сигнатуры методов класса-прокси. Если суперинтерфейс или ссылаемый класс или интерфейс, скажем T, находится в неэкспортированном пакете, модуль T обновляется, чтобы экспортировать пакет T в динамический модуль.
Методы, дублированные в нескольких прокси-интерфейсах
Когда два или более прокси-интерфейса содержат метод с одинаковым именем и сигнатурой параметров, порядок интерфейсов класса-прокси становится существенным. При вызове такого дублирующего метода на экземпляре-прокси, объект Method, переданный обработчику вызовов, необязательно будет тем, чей объявляющий класс может быть приведён к типу ссылки интерфейса, через который метод прокси был вызван. Это ограничение существует, потому что соответствующая реализация метода в сгенерированном классе-прокси не может определить, через какой интерфейс он был вызван. Поэтому, когда дублирующий метод вызывается на экземпляре-прокси, объект Method для метода в самом верхнем интерфейсе, который содержит метод (либо напрямую, либо унаследован через суперинтерфейс) в списке интерфейсов класса-прокси, передаётся обработчику вызовов, независимо от типа ссылки, через который произошёл вызов метода.
Если прокси-интерфейс содержит метод с тем же именем и сигнатурой параметров, что и методы hashCode, equals или toString класса java.lang.Object, при вызове такого метода на экземпляре-прокси объект Method, переданный обработчику вызовов, будет иметь класс-объявитель java.lang.Object. Другими словами, общедоступные, не final методы класса java.lang.Object логически предшествуют всем прокси-интерфейсам для определения, какой объект Method передать обработчику вызовов.
Также обратите внимание, что когда дублирующий метод перенаправляется обработчику вызовов, метод invoke может выбрасывать только типы checked исключений, которые могут быть приведены к одному из типов исключений в разделе throws метода во всех прокси-интерфейсах, через которые он может быть вызван. Если метод invoke выбрасывает checked исключение, которое не приводимо ни к одному из типов исключений, объявленных методом в одном из прокси-интерфейсов, через которые он может быть вызван, тогда необрабатываемое UndeclaredThrowableException будет выброшено при вызове на экземпляре-прокси. Это ограничение означает, что не все типы исключений, возвращаемые при вызове getExceptionTypes на объекте Method, переданном методу invoke, обязательно могут быть успешно выброшены методом invoke.
- Since:
- 1.3
- See Also:
Краткое описание полей
| Модификатор и тип | Поле | Описание |
|---|---|---|
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 для класса прокси, заданного загрузчиком классов и массивом интерфейсов. Класс прокси будет определён заданным загрузчиком классов и будет реализовывать все предоставленные интерфейсы. Если какой-либо из указанных интерфейсов является непубличным, то класс прокси будет непубличным. Если класс прокси для той же перестановки интерфейсов уже был определён загрузчиком классов, то будет возвращён существующий класс прокси; в противном случае динамически сгенерируется и определится загрузчиком классов класс прокси для этих интерфейсов.- Параметры:
-
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 - Все типы, упоминаемые в сигнатурах всех публичных методов указанных интерфейсов и унаследованных их суперинтерфейсами, должны быть видны по имени через указанный загрузчик классов.
- Все непубличные интерфейсы должны находиться в одном пакете и модуле, определяемом указанным загрузчиком классов, и модуль непубличных интерфейсов может обращаться ко всем типам интерфейсов; в противном случае для класса прокси не было бы возможности реализовать все интерфейсы, независимо от того, в каком пакете он определен.
- Для любого набора методов-членов указанных интерфейсов с одинаковой сигнатурой:
- Если тип возвращаемого значения любого из методов является примитивным типом или 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- если аргумент не является экземпляром прокси
© 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/reflect/Proxy.html