Java反射:查找在中声明方法的基类/接口

Java反射:查找在中声明方法的基类/接口,java,reflection,annotations,Java,Reflection,Annotations,我有一个公共API,如: interface Alien { @Help( "Make him say something" ) String speak(); } 以及一种类似于: class Dalek implements Alien { @Override String speak(){ return "Exterminate!"; } } 现在我需要访问基本接口上的注释@Help,但我只有实现/派生类,它可能实现其他接口或扩展其他类 那么,在Java

我有一个公共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 )

不,关于接口,没有“合理的方法”可以做到这一点。问题是没有唯一的“基本”方法。方法声明可以重写一个超类方法,并同时实现多个不相关的接口方法,例如

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; }
    }
}
但请注意,接口支持多重继承,并且冗余的
实现了
规范,例如,您可以根据需要更改上述场景

interface I3 extends I2, I1 {
}
interface I4 extends I2 {
    void foo();
}
class B extends A implements I3, I4, I2 {
    @Override
    public void foo() {}
}
我们会得到

候选I2.foo
候选人I4.foo
候选I2.foo
候选人B.foo
候选人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
时,我们得到一个
方法
对象报告
A
作为其声明类,它不实现任何接口。因此,
方法
对象无法承载预期查找所需的信息类型。注释搜索方法需要更多的信息,如果它应该查找所有接口方法候选者,例如,您可能需要显式地传递实际的


请注意,普通Java操作不需要处理这种复杂性。您可以在实际对象上调用接口方法,无论接口继承层次结构有多复杂,都会在对象的具体类上搜索实现方法,必要时遍历线性超类层次结构(新的
default
方法稍微改变了这一点,但它仍然比您的任务更简单,因为重写的方法仍然与调用无关)


JRE没有为您的任务提供实现。

重复:否。不是。问题要求解释注释是如何工作的。答案说明注释不是继承的。我的问题是如何找到它们(或者更一般地说是覆盖的方法)您好,霍尔格。感谢您全面的回答,并指出在Java中没有单一“声明”的概念。只有几件事:1.“幼稚”代码没有打印出您所说的功能。2.我认为递归调用可以让它不那么幼稚。事实上,我在复制代码后做了更改,但忘记了再次复制。当然,您可以递归地收集所有方法/接口,但是,正如我试图解释的,由于这种可能性,您可能会多次遇到相同的类型继承具有相同超类型的多个接口的方法。然后,如果您喜欢重写方法的注释(如果存在),则必须找出在概念上哪个接口重写了另一个接口。