- 所有已知的实现类:
-
CompositeDataInvocationHandler
,EventHandler
,MBeanServerInvocationHandler
,RemoteObjectInvocationHandler
public interface InvocationHandler
InvocationHandler
是代理实例的调用处理程序实现的接口。
每个代理实例都有一个关联的调用处理程序。当在代理实例上调用方法时,方法调用被编码并分派到其调用处理程序的invoke
方法。
- 自:
- 1.3
- 参见:
-
Method Summary
-
Method Details
-
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()) { // 如果是默认方法,调用它 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")) { // 调用B::m而不是A::m Method bMethod = B.class.getMethod(m.getName(), m.getParameterTypes()); return InvocationHandler.invokeDefault(o, bMethod, params); } });
C
,该接口从其超接口A
继承了方法m
的默认实现,则在代理实例上的接口方法调用"m"
将被分派到调用处理程序的invoke
方法,其中Method
对象参数表示默认方法A::m
。Object proxy = Proxy.newProxyInstance(loader, new Class<?>[] { C.class }, (o, m, params) -> { if (m.isDefault()) { // 行为就像调用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,因为{@code A::m}不是从其代理接口C继承的方法 Method aMethod = A.class.getMethod(m.getName(), m.getParameterTypes()); return InvocationHandler.invokeDefault(o, aMethod params); } }); c.m(...);
C
上成功运行,并调用A::m
。当在新版本的C
上运行时,上述代码将因为C
覆盖了相同方法的实现而导致IllegalArgumentException
,并且代理实例无法访问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
-