我有一个公共API,如:
interface Alien {
@Help( "Make him say something" )
String speak();
}
和类似的实现:
class Dalek implements Alien {
@Override
String speak(){ return "Exterminate!"; }
}
现在我需要访问基接口上的注释@Help
,但我只有实现/派生类,它可以实现其他接口或扩展其他类。
在Java中找到" base"是否有一种理智的方式被覆盖的方法或其他获取该注释的方法?
我正在寻找的伪代码就像:
Method m;
m.getDeclaringMethod().getAnnotation( Help.class );
// or:
m.getAnnotationRecusively( Help.class )
答案 0 :(得分:2)
不,关于接口没有“理智的方式”。问题是没有独特的“基础”方法。方法声明可以覆盖超类方法并同时实现多个不相关的接口方法,例如
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
继承的方法实现所有接口,因此在foo
中查找方法B
时,我们会得到一个Method
对象报告{{ 1}}作为其声明类,它不实现任何接口。因此,A
对象无法为您的预期查找提供所需类型的信息。注释搜索方法需要更多信息,如果它应该找到所有接口方法候选者,例如您可能需要明确传递实际的Method
。
请注意,普通的Java操作不需要处理这种复杂性。您可以在实际对象上调用接口方法,无论接口继承层次结构有多复杂,都会在对象的具体类上搜索实现方法,在必要时遍历线性超类层次结构(新的Class
方法稍微改变一下,但它仍然比你的任务更简单,因为重写的方法仍然与调用无关。)
JRE不提供针对您的任务的实现。