- java.lang.Object
-
- java.lang.reflect.Proxy
-
- 实现的所有接口
-
Serializable
public class Proxyextends Objectimplements 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"
开头的类名空间应该保留给代理类。 - 定义代理类的包和模块指定为below 。
- 代理类是final和非抽象的 。
- 代理类扩展
java.lang.reflect.Proxy
。 - 代理类以相同的顺序实现其创建时指定的接口。 在其
类
对象上调用getInterfaces
将返回包含相同接口列表的数组(按创建时指定的顺序),在其类
对象上调用getMethods
将返回包含这些接口中所有方法的方法
对象的数组,以及调用getMethod
会在代理接口中找到预期的方法。 - 代理类的
ProtectionDomain
与引导类加载器加载的系统类(例如java.lang.Object
,因为代理类的代码由受信任的系统代码生成。 该保护域通常将被授予java.security.AllPermission
。 -
Proxy.isProxyClass
方法可用于确定给定的类是否是代理类。
代理实例具有以下属性:
- 给定代理实例
proxy
和由其代理类实现的其中一个接口Foo
,以下表达式将返回true:proxy instanceof Foo
ClassCastException
操作将成功(而不是抛出ClassCastException
):(Foo) proxy
- 每个代理实例都有一个关联的调用处理程序,即传递给其构造函数的处理程序。 静态
Proxy.getInvocationHandler
方法将返回与作为其参数传递的代理实例关联的调用处理程序。 - 代理实例上的接口方法调用将被编码并调度到调用处理程序的
invoke
方法,如该方法的文档中所述。 - 的调用
hashCode
,equals
,或toString
中声明的方法java.lang.Object
上的代理实例将被编码并分派到调用处理程序的invoke
中相同的方式方法,接口方法调用进行编码和调度,如上所述。 传递给invoke
的方法
对象的声明类将为java.lang.Object
。 从java.lang.Object
继承的代理实例的其他公共方法不会被代理类覆盖,因此这些方法的调用行为与java.lang.Object
实例java.lang.Object
。
Package and Module Membership of Proxy Class
选择代理类所属的包和模块,使得代理类的可访问性与代理接口的可访问性一致。 具体而言,通过getProxyClass(ClassLoader, Class[])
或newProxyInstance(ClassLoader, Class[], InvocationHandler)
方法定义的代理类的包和模块成员资格指定如下:- 如果所有代理接口都在导出或打开的包中:
- 如果所有代理接口都是公共的 ,则代理类在指定加载器的unnamed module导出的包中是公共的 。 包的名称未指定。
- 如果所有的代理接口的至少一个是非公 ,则代理类是在非公共接口的包和模块的非公开 。 所有非公共接口必须在同一个包和模块中; 否则,代理他们是not possible 。
- 如果至少有一个代理接口位于未导出且未 打开的包中 :
- 如果所有代理接口都是公共的 ,则代理类在未导出的 非打开包中是公共的dynamic module.未指定包和模块的名称。
- 如果所有的代理接口的至少一个是非公 ,则代理类是在非公共接口的包和模块的非公开 。 所有非公共接口必须在同一个包和模块中; 否则,代理他们是not possible 。
请注意,如果具有混合可访问性的代理接口(例如,导出的公共接口和非导出的非公共接口)由同一实例代理,则代理类的可访问性由最不可访问的代理接口控制。
请注意,任意代码都可以使用
setAccessible
获取对打开包中的代理类的访问权限,而非开放包中的代理类永远不会被代理类模块外部的代码访问。在整个说明书中,“未导出的包”是指未导出到所有模块的包,“非打开包”是指不对所有模块开放的包。 具体来说,这些术语指的是一个包,它不是由其包含的模块导出/打开,也不是由其包含的模块以合格的方式导出/打开。
Dynamic Modules
动态模块是在运行时生成的命名模块。 动态模块中定义的代理类被封装,任何模块都无法访问。 在动态模块中的代理类上调用
Constructor.newInstance(Object...)
将抛出IllegalAccessException
; 应该使用Proxy.newProxyInstance
方法。动态模块可以读取代理类的所有超接口的模块以及代理类的所有公共方法签名所引用的类型的模块。 如果超级接口或引用类型(例如
T
)位于非导出包中,则更新T的T
以将包T
导出到动态模块。方法在多个代理接口中重复
当两个或多个代理接口包含具有相同名称和参数签名的方法时,代理类接口的顺序变得很重要。 在代理实例上调用此类重复方法时 ,传递给调用处理程序的
方法
对象不一定是其声明类可从调用代理方法的接口的引用类型分配的对象。 存在此限制是因为生成的代理类中的相应方法实现无法确定通过哪个接口调用它。 因此,当在代理实例上调用重复方法时,在代理类的接口列表中包含该方法(直接或通过超接口继承)的最前面接口中的方法的方法
对象将传递给调用处理程序的invoke
方法,无论方法调用发生的引用类型如何。如果代理接口包含具有相同的名称和参数签名的方法
hashCode
,equals
,或toString
的方法java.lang.Object
,当这种方法在代理实例调用时,方法
传递到调用处理程序对象将java.lang.Object
作为其宣布上课。 换句话说,java.lang.Object
的公共非final方法逻辑上位于所有代理接口之前,用于确定将哪个方法
对象传递给调用处理程序。另请注意,当将重复方法分派给调用处理程序时,
invoke
方法可能只会抛出可分配给可在其调用的所有代理接口中的方法的throws
子句中的一个异常类型的已检查异常类型。通过。 如果invoke
方法抛出一个已检查的异常,该异常不能分配给该方法在其中一个可以调用的代理接口中声明的任何异常类型,则代理实例上的调用将抛出未经检查的UndeclaredThrowableException
。 此限制意味着,并非所有通过调用返回的异常类型getExceptionTypes
开方法
传递给对象invoke
方法一定可以成功地抛出invoke
方法。- 从以下版本开始:
- 1.3
- 另请参见:
-
InvocationHandler
, Serialized Form
-
-
字段汇总
字段 变量和类型 字段 描述 protected InvocationHandler
h
此代理实例的调用处理程序。
-
构造方法摘要
构造方法 变量 构造器 描述 protected
Proxy(InvocationHandler h)
从子类(通常是动态代理类)构造一个新的Proxy
实例,并为其调用处理程序指定值。
-
方法摘要
所有方法 静态方法 具体的方法 弃用的方法 变量和类型 方法 描述 static InvocationHandler
getInvocationHandler(Object proxy)
返回指定代理实例的调用处理程序。static 类<?>
getProxyClass(ClassLoader loader, 类<?>... interfaces)
已过时。在命名模块中生成的代理类被封装,并且其模块外部的代码无法访问。static boolean
isProxyClass(类<?> cl)
如果给定的类是代理类,则返回true。static Object
newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h)
返回指定接口的代理实例,该接口将方法调用分派给指定的调用处理程序。
-
-
-
字段详细信息
-
h
protected InvocationHandler h
此代理实例的调用处理程序。
-
-
构造方法详细信息
-
Proxy
protected Proxy(InvocationHandler h)
从子类(通常是动态代理类)构造一个新的Proxy
实例,并为其调用处理程序指定值。- 参数
-
h
- 此代理实例的调用处理程序 - 异常
-
NullPointerException
- 如果给定的调用处理程序h
是null
。
-
-
方法详细信息
-
getProxyClass
@Deprecatedpublic static 类<?> getProxyClass(ClassLoader loader, 类<?>... interfaces) throws IllegalArgumentException
Deprecated.Proxy classes generated in a named module are encapsulated and not accessible to code outside its module.Constructor.newInstance
will throwIllegalAccessException
when it is called on an inaccessible proxy class. UsenewProxyInstance(ClassLoader, Class[], InvocationHandler)
to create a proxy instance instead.给定类加载器和接口数组,返回代理类的java.lang.Class
对象。 代理类将由指定的类加载器定义,并将实现所有提供的接口。 如果任何给定接口是非公共接口,则代理类将是非公共接口。 如果类加载器已经定义了相同的接口排列的代理类,那么将返回现有的代理类; 否则,将动态生成这些接口的代理类,并由类加载器定义。- 参数
-
loader
- 用于定义代理类的类加载器 -
interfaces
- 要实现的代理类的接口列表 - 结果
- 在指定的类加载器中定义并实现指定接口的代理类
- 异常
-
IllegalArgumentException
- 如果违反了参数 restrictions中的任何一个 -
SecurityException
- 如果存在安全管理器s且满足以下任何条件:- 给定的
loader
是null
,调用者的类加载器不是null
,调用s.checkPermission
和RuntimePermission("getClassLoader")
权限拒绝访问。 - 对于每个代理接口,
intf
,调用者的类加载器与intf
的类加载器或祖先不同,并且调用s.checkPackageAccess()
拒绝访问intf
。
- 给定的
-
NullPointerException
- 如果interfaces
数组参数或其任何元素是null
- 另请参见:
- Package and Module Membership of Proxy Class
-
newProxyInstance
public static Object newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h)
返回指定接口的代理实例,该接口将方法调用分派给指定的调用处理程序。IllegalArgumentException
will be thrown if any of the following restrictions is violated:- 给定
interfaces
数组中的所有类
对象必须表示接口,而不是类或基元类型。 -
interfaces
数组中没有两个元素可以引用相同的类
对象。 - 所有接口类型必须通过指定的类加载器按名称可见。 换句话说,对于类加载器
cl
和每个接口i
,以下表达式必须为true:Class.forName(i.getName(), false, cl) == i
- 指定接口的所有公共方法签名引用的所有类型以及由其超接口继承的类型必须通过指定的类加载器按名称可见。
- 所有非公共接口必须位于同一个包和模块中,由指定的类加载器定义,非公共接口的模块可以访问所有接口类型; 否则,代理类无法实现所有接口,无论它定义在哪个包中。
- 对于具有相同签名的指定接口的任何成员方法集:
- 如果任何方法的返回类型是基本类型或void,则所有方法必须具有相同的返回类型。
- 否则,其中一个方法必须具有可分配给其余方法的所有返回类型的返回类型。
- 生成的代理类不得超过虚拟机对类强加的任何限制。 例如,VM可以将类可以实现的接口数量限制为65535; 在这种情况下,
interfaces
阵列的大小不得超过65535。
请注意,指定代理接口的顺序很重要:对具有相同接口组合但顺序不同的代理类的两个请求将导致两个不同的代理类。
- 参数
-
loader
- 用于定义代理类的类加载器 -
interfaces
- 要实现的代理类的接口列表 -
h
- 调度方法调用的调用处理程序 - 结果
- 具有指定的代理类调用处理程序的代理实例,该代理类由指定的类加载器定义并实现指定的接口
- 异常
-
IllegalArgumentException
- 如果违反了参数 restrictions中的任何一个 -
SecurityException
- 如果存在安全管理器s且满足以下任何条件:- 给定的
loader
是null
,调用者的类加载器不是null
,调用s.checkPermission
和RuntimePermission("getClassLoader")
权限拒绝访问; - 对于每个代理接口,
intf
,调用者的类加载器与intf
的类加载器或祖先不同,并且调用s.checkPackageAccess()
拒绝访问intf
; - 任何给定的代理接口的是非公和呼叫者类是不在同一runtime package作为本次非公开接口的调用
s.checkPermission
与ReflectPermission("newProxyInPackage.{package name}")
权限拒绝访问。
- 给定的
-
NullPointerException
- 如果interfaces
数组参数或其任何元素是null
,或者如果调用处理程序h
是null
- 另请参见:
- Package and Module Membership of Proxy Class
- 给定
-
isProxyClass
public static boolean isProxyClass(类<?> cl)
如果给定的类是代理类,则返回true。- Implementation Note:
- 此方法的可靠性对于使用它来做出安全决策的能力很重要,因此它的实现不应仅测试所讨论的类是否扩展为
Proxy
。 - 参数
-
cl
- 要测试的类 - 结果
-
true
如果类是代理类,false
- 异常
-
NullPointerException
- 如果cl
是null
-
getInvocationHandler
public static InvocationHandler getInvocationHandler(Object proxy) throws IllegalArgumentException
返回指定代理实例的调用处理程序。- 参数
-
proxy
- 用于返回调用处理程序的代理实例 - 结果
- 代理实例的调用处理程序
- 异常
-
IllegalArgumentException
- 如果参数不是代理实例 -
SecurityException
- 如果存在安全管理器 s且调用者的类加载器与调用处理程序的类加载器的祖先或调用处理程序的祖先不同,则调用s.checkPackageAccess()
将拒绝访问调用处理程序的类。
-
-