[英]Get parent method with fixed generic parameter by reflection
让我们有这个类结构:
abstract class Event {}
class EventImpl extends Event {}
class Foo<T extends Event> {
public void foo(T event) {}
}
class FooImpl extends Foo<EventImpl> {
}
我试图通过反射从FooImpl
实例中找到Method
foo
。 我认为这应该工作:
FooImpl fooImpl = new FooImpl();
Class clazz = fooImpl.getClass();
Method foo = clazz.getMethod("foo", EventImpl.class);
但是,我得到一个NoSuchMethodException
。 似乎固定为EventImpl
的泛型参数T
不能被识别为方法参数,因为如果我尝试以这种方式找到方法,那么工作正常:
Method fooParent = clazz.getMethod("foo", Event.class);
这种行为是正常的还是我在这里遗漏了什么? 谢谢您的帮助。
只是帮助重现错误的基本测试:
@Test
public void test() throws Exception {
FooImpl fooImpl = new FooImpl();
// Method foo of class FooImpl need to be called with parameter EventImpl
fooImpl.foo(new EventImpl());
Class clazz = fooImpl.getClass();
Method fooParent = clazz.getMethod("foo", Event.class); // OK
Method foo = clazz.getMethod("foo", EventImpl.class); // NoSuchMethodException
}
这是由于泛型的类型擦除 。
来自Oracle Docs:
如果类型参数是无界的,则将泛型类型中的所有类型参数替换为其边界或对象。 因此,生成的字节码仅包含普通的类,接口和方法。
由于Reflection
是一种运行时现象,由于泛型的类型擦除, foo
的参数被替换为Event
(因为它受T extends Event
约束)。
因此,您必须传递Event.class
作为参数。
这里的关键字是: 桥接方法 。
编译时, FooImpl
不会直接使用Event
类型的参数公开方法foo
,但它可能会生成一个额外的(桥接)方法(作为类型擦除过程的一部分),以确保子类型按预期工作:
public void foo(Event event) {
foo((EventImpl) event);
}
private void foo(EventImpl eventImpl) {
}
在运行时,当您的Reflection snipped将被执行并且在类型擦除已经发生之后, T
类型参数将已经成功替换为Event
,但是在调用时,bridge方法将帮助委托给使用的原始foo
方法一个EventImpl
参数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.