Класс 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), определяется следующим образом: - Если все прокси-интерфейсы находятся в экспортируемых или открытых пакетах:
- если все прокси-интерфейсы являются public, то прокси-класс является public в безоговорочно экспортируемом, но неоткрытом пакете. Имя пакета и имя модуля не определены.
- если хотя бы один из всех прокси-интерфейсов является non-public, то прокси-класс является non-public в пакете и модуле непубличных интерфейсов. Все непубличные интерфейсы должны находиться в одном и том же пакете и модуле; в противном случае создание прокси для них невозможно.
- Если хотя бы один прокси-интерфейс находится в пакете, который является неэкспортируемым и неоткрытым:
- если все прокси-интерфейсы являются public, то прокси-класс является public в неэкспортируемом, неоткрытом пакете динамического модуля. Имена пакета и модуля не определены.
- если хотя бы один из всех прокси-интерфейсов является non-public, то прокси-класс является non-public в пакете и модуле непубличных интерфейсов. Все непубличные интерфейсы должны находиться в одном и том же пакете и модуле; в противном случае создание прокси для них невозможно.
Обратите внимание: если прокси-интерфейсы со смешанной доступностью — например, экспортируемый открытый интерфейс и неэкспортируемый непубличный интерфейс — проксируются одним и тем же экземпляром, то доступность прокси-класса определяется наименее доступным прокси-интерфейсом.
Обратите внимание, что произвольный код может получить доступ к прокси-классу в открытом пакете с помощью setAccessible, тогда как прокси-класс в неоткрытом пакете никогда не доступен коду вне модуля прокси-класса.
В этой спецификации под «неэкспортируемым пакетом» понимается пакет, который не экспортирован во все модули, а под «неоткрытым пакетом» — пакет, который не открыт для всех модулей. В частности, эти термины относятся к пакету, который либо не экспортирован/открыт содержащим его модулем, либо экспортирован/открыт содержащим его модулем с квалификацией.
Динамические модули
Динамический модуль — это именованный модуль, генерируемый во время выполнения. Прокси-класс, определенный в динамическом модуле, инкапсулирован и недоступен ни для одного модуля. Вызов Constructor.newInstance(Object...) для прокси-класса в динамическом модуле выбросит IllegalAccessException; вместо этого следует использовать метод Proxy.newProxyInstance.
Динамический модуль может читать модули всех суперинтерфейсов прокси-класса, а также модули классов и интерфейсов, на которые ссылаются все сигнатуры открытых методов прокси-класса. Если суперинтерфейс или упоминаемый класс/интерфейс, например T, находится в неэкспортируемом пакете, модуль класса/интерфейса T обновляется для экспорта пакета T в динамический модуль.
Методы, дублирующиеся в нескольких прокси-интерфейсах
Если два или более прокси-интерфейса содержат метод с одинаковым именем и сигнатурой параметров, порядок интерфейсов прокси-класса становится существенным. При вызове такого дублирующегося метода на прокси-экземпляре объект Method, переданный обработчику вызовов, не обязательно будет тем, чей класс объявления совместим по присваиванию с ссылочным типом интерфейса, через который был вызван метод прокси. Это ограничение существует потому, что соответствующая реализация метода в сгенерированном прокси-классе не может определить, через какой интерфейс она была вызвана. Поэтому при вызове дублирующегося метода на прокси-экземпляре объект Method для метода из самого первого интерфейса в списке интерфейсов прокси-класса, содержащего этот метод (напрямую или унаследованного через суперинтерфейс), передается в метод invoke обработчика вызовов независимо от ссылочного типа, через который произошел вызов метода.
Если прокси-интерфейс содержит метод с тем же именем и сигнатурой параметров, что и методы hashCode, equals или toString класса java.lang.Object, то при вызове такого метода на прокси-экземпляре объект Method, переданный обработчику вызовов, будет иметь java.lang.Object в качестве класса объявления. Иными словами, открытые не-final методы класса 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 |
Возвращает прокси-экземпляр для указанных интерфейсов, который диспетчеризирует вызовы методов указанному обработчику вызовов. |
Методы, объявленные в классе Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait | Модификатор и тип | Метод | Описание |
|---|---|---|
protected Object |
clone() |
Создает и возвращает копию этого объекта. |
boolean |
equals |
Указывает, равен ли какой-либо другой объект этому объекту. |
protected void |
finalize() |
Устарело, для удаления: этот элемент API подлежит удалению в будущей версии. Финализация устарела и подлежит удалению в будущем выпуске. |
final Class |
getClass() |
Возвращает класс среды выполнения этого объекта Object. |
int |
hashCode() |
Возвращает значение хэш-кода для этого объекта. |
final void |
notify() |
Пробуждает один поток, ожидающий на мониторе этого объекта. |
final void |
notifyAll() |
Пробуждает все потоки, ожидающие на мониторе этого объекта. |
String |
toString() |
Возвращает строковое представление объекта. |
final void |
wait() |
Заставляет текущий поток ждать, пока он не будет разбужен, обычно посредством оповещения или прерывания. |
final void |
wait |
Заставляет текущий поток ожидать, пока он не будет пробужден, как правило, будучи оповещенным или прерванным, или пока не истечет определенное время. |
final void |
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 для прокси-класса по заданному загрузчику классов и массиву интерфейсов. Прокси-класс будет определен указанным загрузчиком классов и будет реализовывать все предоставленные интерфейсы. Если какой-либо из указанных интерфейсов является непубличным, прокси-класс также будет непубличным. Если прокси-класс для той же комбинации интерфейсов уже был определен загрузчиком классов, будет возвращен существующий прокси-класс; в противном случае прокси-класс для этих интерфейсов будет динамически сгенерирован и определен загрузчиком классов.- Параметры:
-
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- загрузчик классов для определения прокси-класса; может бытьnullдля обозначения загрузчика классов начальной загрузки -
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.