- 所有已知的实现类:
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
是null
Throwable
- 默认方法抛出的任何东西- 看Java 虚拟机规范:
-
5.4.3.方法解析
- 自从:
- 16
-