- java.lang.Object
-
- java.lang.reflect.Proxy
-
- All Implemented Interfaces:
-
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"
开头的类名空间。 - 指定代理类的包和模块指定为below 。
- 代理类是最终的和非抽象的 。
- 代理类扩展为
java.lang.reflect.Proxy
。 - 代理类完全按照相同的顺序实现其创建时指定的接口。 调用
getInterfaces
其上Class
对象将返回包含接口的同一列表的阵列(在其创建时指定的顺序),调用getMethods
其上Class
对象将返回的数组方法
对象,其中包括所有的在这些接口的方法,以及调用getMethod
将会在代理接口中找到可以预期的方法。 - 代理类的
ProtectionDomain
与引导类加载器加载的系统类(例如java.lang.Object
,因为代理类的代码是由可信系统代码生成的。 这个保护域通常会被授予java.security.AllPermission
。 - 可以使用
Proxy.isProxyClass
方法来确定给定的类是否是代理类。
代理实例具有以下属性:
- 给定代理实例
proxy
和由其代理类实现的接口Foo
,以下表达式将返回true:proxy instanceof Foo
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
的公共非最终方法逻辑上先于所有的代理接口,以确定哪个方法
对象传递给调用处理程序。还要注意,当重复方法被分派到调用处理程序,该
invoke
方法只能抛出可分配到的异常类型的一个检查的异常类型throws
方法的条款中所有可调用的代理接口通过。 如果invoke
方法抛出一个检查的异常,该异常不能分配给方法在其可以被调用的代理接口之一中声明的任何异常类型,那么在代理实例上的调用将抛出未经检查的UndeclaredThrowableException
。 此限制意味着,并非所有通过调用返回的异常类型的getExceptionTypes
的上方法
传递给对象invoke
方法一定可以成功地抛出invoke
方法。- 从以下版本开始:
- 1.3
- 另请参见:
-
InvocationHandler
, Serialized Form
-
-
Field Summary
Fields Modifier and Type Field 描述 protected InvocationHandler
h
该代理实例的调用处理程序。
-
构造方法摘要
构造方法 Modifier Constructor 描述 protected
Proxy(InvocationHandler h)
从具有指定值的子类(通常为动态代理类)构造新的Proxy
实例。
-
方法摘要
所有方法 静态方法 具体的方法 弃用的方法 Modifier and Type 方法 描述 static InvocationHandler
getInvocationHandler(Object proxy)
返回指定代理实例的调用处理程序。static Class<?>
getProxyClass(ClassLoader loader, Class<?>... interfaces)
已过时。在命名模块中生成的代理类被封装,并且不能访问其模块外的代码。Constructor.newInstance
将在不可访问的代理类上调用IllegalAccessException
。 使用newProxyInstance(ClassLoader, Class[], InvocationHandler)
代替创建一个代理实例。static boolean
isProxyClass(Class<?> cl)
如果给定的类是代理类,则返回true。static Object
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
返回指定接口的代理实例,该代理实例将方法调用分派给指定的调用处理程序。
-
-
-
字段详细信息
-
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
- 如果任何 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, Class<?>[] interfaces, InvocationHandler h)
返回指定接口的代理实例,该代理实例将方法调用分派给指定的调用处理程序。IllegalArgumentException
will be thrown if any of the following restrictions is violated:- 给定的
interfaces
数组中的所有Class
对象必须表示接口,而不是类或基本类型。 -
interfaces
阵列中没有两个元素可能指向相同的Class
对象。 - 所有接口类型必须通过指定的类加载器的名称可见。 换句话说,对于类加载器
cl
和每个接口i
,以下表达式必须为真: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(Class<?> cl)
如果给定的类是代理类,则返回true。- Implementation Note:
-
这种方法的可靠性对于使用它来做出安全决策的能力很重要,所以它的实现不应该只是测试所讨论的类是否扩展了
Proxy
。 - 参数
-
cl
- 要测试的班级 - 结果
-
true
如果该类是代理类,否则为false
- 异常
-
NullPointerException
- 如果cl
是null
-
getInvocationHandler
public static InvocationHandler getInvocationHandler(Object proxy) throws IllegalArgumentException
返回指定代理实例的调用处理程序。- 参数
-
proxy
- 用于返回调用处理程序的代理实例 - 结果
- 代理实例的调用处理程序
- 异常
-
IllegalArgumentException
- 如果参数不是代理实例 -
SecurityException
- if a security manager, s, is present and the caller's class loader is not the same as or an ancestor of the class loader for the invocation handler and invocation ofs.checkPackageAccess()
denies access to the invocation handler's class.
-
-