不,在接口方面没有“理智的方法”可以做到这一点。问题是没有唯一的“基础”方法。一个方法声明可以覆盖一个超类方法,同时实现多个不相关的接口方法,例如
class A {
public void foo() {}
}
interface I1 {
void foo();
}
interface I2 {
void foo();
}
class B extends A implements I1, I2 {
@Override
public void foo() {}
}
那么,当你使用这种幼稚的方法时:
public static void printCandidates(Method m) {
Class<?> cl=m.getDeclaringClass();
String name=m.getName(); Class<?>[] param=m.getParameterTypes();
for(Class<?> i: cl.getInterfaces()) try {
Method ifM=i.getMethod(name, param);
System.out.println("candidate "+ifM.getDeclaringClass().getName()+'.'+name);
} catch(NoSuchMethodException ex) { ex.printStackTrace();}
for(;;) {
System.out.println("candidate "+cl.getName()+'.'+name);
cl=cl.getSuperclass();
if(cl==null) break;
try { m=cl.getMethod(name, param); }
catch(NoSuchMethodException ex) { break; }
}
}
并调用printCandidates(new B().getClass().getMethod("foo"));,它将打印
candidate I1.foo
candidate I2.foo
candidate B.foo
candidate A.foo
但请注意,接口支持多重继承以及冗余的implements 规范,例如您可以将上述情况更改为
interface I3 extends I2, I1 {
}
interface I4 extends I2 {
void foo();
}
class B extends A implements I3, I4, I2 {
@Override
public void foo() {}
}
我们会得到
candidate I2.foo
candidate I4.foo
candidate I2.foo
candidate B.foo
candidate A.foo
注意,I2.foo 声明如何出现两次,但是当I4.foo 有注释时,它应该具有优先权,因为它会覆盖I2.foo,而I1.foo 不会出现,但需要考虑而不是被覆盖。支持多重继承、可能冗余指定的接口和一些包含覆盖规范的接口的整个逻辑非常复杂。但情况变得更糟:
class B extends A implements I3, I4, I2 {
}
进行此更改后,我们得到:
candidate A.foo
没有别的。 B 正在使用从 A 继承的方法实现所有接口,因此当在 B 中查找方法 foo 时,我们会得到一个 Method 对象报告 A 作为它的声明类,它没有实现任何接口。因此,Method 对象无法为您的预期查找携带所需类型的信息。注释搜索方法需要更多的信息,如果它应该找到所有接口方法候选,例如。您可能需要明确传递实际的Class。
请注意,普通的 Java 操作不需要处理这种复杂性。您可以在实际对象上调用接口方法,无论接口继承层次结构多么复杂,都会在对象的具体类上搜索实现方法,必要时遍历线性超类层次结构(新的default 方法改变了这一点有点,但它仍然是你的任务更简单,因为重写的方法仍然与调用无关)。
JRE 没有为您的任务类型提供实现。