- 所有已知的实现类:
CompositeDataInvocationHandler,EventHandler,MBeanServerInvocationHandler,RemoteObjectInvocationHandler
public interface InvocationHandler
InvocationHandler是接口实现的调用处理程序一个代理实例。
每个代理实例都有一个关联的调用处理程序。当在代理实例上调用方法时,方法调用被编码并分派到其调用处理程序的 invoke 方法。
- 自从:
- 1.3
- 参见:
-
方法总结
-
方法详情
-
invoke
处理代理实例上的方法调用并返回结果。当在与其关联的代理实例上调用方法时,将在调用处理程序上调用此方法。- 参数:
proxy- 调用该方法的代理实例method- 与在代理实例上调用的接口方法对应的Method实例。Method对象的声明类将是声明该方法的接口,它可能是代理类通过其继承该方法的代理接口的超接口。args- 包含在代理实例的方法调用中传递的参数值的对象数组,或者null如果接口方法不带参数。原始类型的参数包装在适当的原始包装类的实例中,例如java.lang.Integer或java.lang.Boolean。- 返回:
-
从代理实例上的方法调用返回的值。如果接口方法声明的返回类型是原始类型,则该方法返回的值必须是对应原始包装类的实例;否则,它必须是可分配给声明的返回类型的类型。如果此方法返回的值为
null并且接口方法的返回类型为原始类型,则代理实例上的方法调用将抛出NullPointerException。如果此方法返回的值与上述接口方法声明的返回类型不兼容,则代理实例上的方法调用将抛出ClassCastException。 - 抛出:
Throwable- 从代理实例的方法调用中抛出的异常。异常的类型必须可分配给接口方法的throws子句中声明的任何异常类型或未检查的异常类型java.lang.RuntimeException或java.lang.Error。如果此方法抛出一个不可分配给接口方法的throws子句中声明的任何异常类型的已检查异常,则包含此方法抛出的异常的UndeclaredThrowableException将由方法调用抛出代理实例。- 参见:
-
invokeDefault
使用给定的参数在给定的proxy实例上调用指定的默认方法。给定的method必须是在proxy类的代理接口中声明的默认方法,或者直接或间接继承自其超接口。调用此方法的行为就像从代理类执行
invokespecial指令一样,以代理接口中的默认方法为目标。这等效于调用:X.super.m(A* a),其中X是代理接口,对X.super::m(A*)的调用解析为给定的method。示例:接口
A和B都声明了方法m的默认实现。接口C扩展了A并从其超接口A继承了默认方法m。
下面创建一个实现interface A { default T m(A a) { return t1; } } interface B { default T m(A a) { return t2; } } interface C extends A {}A并调用默认方法A::m的代理实例。
如果代理实例同时实现Object proxy = Proxy.newProxyInstance(loader, new Class<?>[] { A.class }, (o, m, params) -> { if (m.isDefault()) { // if it's a default method, invoke it return InvocationHandler.invokeDefault(o, m, params); } });A和B,它们都提供方法m的默认实现,调用处理程序可以通过invokeDefault方法将方法调用分派给A::m或B::m。例如,以下代码将方法调用委托给B::m。
如果代理实例实现从其超接口Object proxy = Proxy.newProxyInstance(loader, new Class<?>[] { A.class, B.class }, (o, m, params) -> { if (m.getName().equals("m")) { // invoke B::m instead of A::m Method bMethod = B.class.getMethod(m.getName(), m.getParameterTypes()); return InvocationHandler.invokeDefault(o, bMethod, params); } });A继承默认方法m的C,则"m"上的接口方法调用将分派到调用处理程序的invoke方法,其中Method对象参数代表默认方法A::m。
在这个Object proxy = Proxy.newProxyInstance(loader, new Class<?>[] { C.class }, (o, m, params) -> { if (m.isDefault()) { // behaves as if calling C.super.m(params) return InvocationHandler.invokeDefault(o, m, params); } });proxy上调用方法"m"的行为就像调用C.super::m并且解析为调用A::m一样。如果现有代码试图调用
invokeDefault以调用默认方法,则添加默认方法或将方法从抽象更改为默认可能会导致异常。例如,如果修改C以实现默认方法m:
上面使用修改后的interface C extends A { default T m(A a) { return t3; } }C创建代理实例proxy的代码将无一例外地运行,并将导致调用C::m而不是A::m。以下是创建
C的代理实例的另一个示例,调用处理程序调用invokeDefault方法来调用A::m:
上面的代码使用旧版本的C c = (C) Proxy.newProxyInstance(loader, new Class<?>[] { C.class }, (o, m, params) -> { if (m.getName().equals("m")) { // IllegalArgumentException thrown as {@code A::m} is not a method // inherited from its proxy interface C Method aMethod = A.class.getMethod(m.getName(), m.getParameterTypes()); return InvocationHandler.invokeDefault(o, aMethod params); } }); c.m(...);C成功运行,并调用了A::m。当使用新版本的C运行时,上述代码将因IllegalArgumentException而失败,因为C覆盖了相同方法的实现,而代理实例无法访问A::m。- API 注意:
proxy参数的类型为Object而不是Proxy以便于InvocationHandler::invoke实现无需强制转换即可直接调用。- 参数:
proxy- 要在其上调用默认方法的Proxy实例method- 对应于在代理类的代理接口中声明或直接或间接从其超接口继承的默认方法的Method实例args- 用于方法调用的参数;如果该方法所需的形式参数的数量为零,则可以是null。- 返回:
- 从方法调用返回的值
- 抛出:
IllegalArgumentException- 如果以下任何条件为true:proxy不是 代理实例;或者- 给定的
method不是在代理类的代理接口中声明的默认方法,也不是从其任何超接口继承的;或者 - 给定的
method被代理接口直接或间接覆盖,并且对命名方法的方法引用永远不会解析为给定的method;或者 - 给定的
args数组的长度与要调用的方法的参数数量不匹配;或者 - 如果相应的方法参数类型是原始类型,则任何
args元素都无法进行拆箱转换;或者,如果在可能的拆箱之后,无法将任何args元素分配给相应的方法参数类型。
IllegalAccessException- 如果调用者类无法访问指定默认方法的声明类NullPointerException- 如果proxy或method是nullThrowable- 默认方法抛出的任何东西- 看Java 虚拟机规范:
-
5.4.3.方法解析
- 自从:
- 16
-