我有一个SubClass
和一个SuperClass
,还有一个注释DocAnnotation
。我需要拨打SubClass.foo()
来获取SubClass
和SuperClass
的所有课程注释。这些类的定义如下:
package Code
import Annotations.DocAnnotation;
import java.util.Arrays;
@DocAnnotation("Super Annotation")
public class SuperClass {
public void foo() {
System.out.println(Arrays.toString(this.getClass().getAnnotations()));
System.out.println(Arrays.toString(this.getClass().getDeclaredAnnotations()));
}
}
package Code;
import Annotations.DocAnnotation;
@DocAnnotation("Sub Annotation")
public class SubClass extends SuperClass{
}
package Annotations;
import java.lang.annotation.Inherited;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(DocAnnotations.class)
public @interface DocAnnotation {
String value();
}
运行SubClass.foo我希望同时看到"Super Annotation"
和"Sub Annotation"
,但我只看到[@Annotations.DocAnnotation(value=Sub Annotation)]
。我误解了@inherited做了什么,或者我做错了什么?
编辑:
将注释@DocAnnotation("Super Annotation")
添加到SubClass
后(它与SuperClass
中的注释相同)实际上会显示两次,一次用于SubClass
一次用于SuperClass
!现在我几乎可以肯定我误解了一些事情......
答案 0 :(得分:2)
你得到这个注释错了。 javadoc明确指出:
表示自动继承注释类型。如果注释类型声明中存在Inherited元注释,并且用户在类声明上查询注释类型,并且类声明没有此类型的注释,则将自动查询类的超类以获取注释类型。
换句话说:如果你查询子类,那么你会发现超类被注释。但是在“OO意义”中,不意味着继承。如果要查看两个注释,则必须编写代码,以手动检查类继承树中的每个类。
答案 1 :(得分:2)
这似乎是预期的行为,或者至少它被指定以这种方式工作(doc):
如果用户在类声明上查询注释类型,并且类声明没有此类型的注释,则将自动查询类的超类以获取注释类型
换句话说,由于SubClass
已经注明@DocAnnotation
,因此不会查询超类。
在进一步检查时,行为似乎有点奇怪,特别是在尝试使用包含注释类型之后。我想出了以下示例,其中说明了这一点(link):
import java.lang.annotation.*;
import java.util.*;
@Inherited
@Repeatable(Container.class)
@Retention(RetentionPolicy.RUNTIME)
@interface Ann {
String value();
}
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Container {
Ann[] value();
}
// Basic case. Result is that
// only @Ann("2") is present on
// ExhibitASub.
@Ann("1")
class ExhibitASuper {
}
@Ann("2")
class ExhibitASub extends ExhibitASuper {
}
// Because this case results in the
// @Container being present on ExhibitBSuper,
// rather than @Ann, all three annotations
// end up appearing on ExhibitBSub.
@Ann("1")
@Ann("2")
class ExhibitBSuper {
}
@Ann("3")
class ExhibitBSub extends ExhibitBSuper {
}
// Similar to the preceding case, by
// forcing the use of @Container, both
// annotations are present on ExhibitCSub.
@Container(@Ann("1"))
class ExhibitCSuper {
}
@Ann("2")
class ExhibitCSub extends ExhibitCSuper {
}
// Yet when we force both to use @Container,
// only @Container(@Ann("2")) is present on
// ExhibitDSub.
@Container(@Ann("1"))
class ExhibitDSuper {
}
@Container(@Ann("2"))
class ExhibitDSub extends ExhibitDSuper {
}
class Main {
public static void main(String[] args) {
for (Class<?> cls : Arrays.asList(ExhibitASub.class,
ExhibitBSub.class,
ExhibitCSub.class,
ExhibitDSub.class)) {
System.out.printf("%s:%n", cls);
for (Annotation ann : cls.getAnnotations()) {
System.out.printf(" %s%n", ann);
}
System.out.println();
}
}
}
其输出如下:
class ExhibitASub:
@Ann(value=2)
class ExhibitBSub:
@Container(value=[@Ann(value=1), @Ann(value=2)])
@Ann(value=3)
class ExhibitCSub:
@Container(value=[@Ann(value=1)])
@Ann(value=2)
class ExhibitDSub:
@Container(value=[@Ann(value=2)])
请注意,对于B和C,我们在超类和子类上都看到了注释。据推测,这是因为(在严格意义上)超类上存在的注释与子类上存在的注释具有不同的类型。请注意,对于D,我们返回仅查看子类注释,因为两个类都使用容器类型。
在某些情况下,明确使用包含注释类型可能是一种解决方法,但由于案例D,它不是一般解决方案。
我可能会在明天提交错误报告,因为这看起来非常不受欢迎。由于@Inherited
早于@Repeatable
,因此此行为可能来自之前的版本,但这种情况不会发生。