为什么@Repeatable注解不能继承接口
Why can @Repeatable Annotations not be inherited from interfaces
在 Java 中标记为 @Inherited
的注释仅在注释 classes:
时有效
Note that this meta-annotation type has no effect if the annotated
type is used to annotate anything other than a class. Note also that
this meta-annotation only causes annotations to be inherited from
superclasses; annotations on implemented interfaces have no effect.
因此,使用 @Inherited
注释进行注释的接口或方法不会导致实现 classes/methods 也使用该注释进行注释。原因很可能是,如果 class 层次结构中有多个注释,如 here.
所述,编译器将不知道选择哪个注释
现在Java8引入了新的注解@Repeatable
。我认为取消上述对标记为 @Inherited
和 @Repeatable
的注释的限制是很自然的,因为编译器随后应该能够将冲突的注释添加到 @Repeatable
注释。
给定以下示例:
import java.lang.annotation.Inherited;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@interface RepeatableAnnotations {
RepeatableAnnotation[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@Repeatable(RepeatableAnnotations.class)
@interface RepeatableAnnotation {
String value();
}
@RepeatableAnnotation("A")
interface IntefaceA {}
@RepeatableAnnotation("B")
interface IntefaceB {}
@RepeatableAnnotation("C")
@RepeatableAnnotation("D")
public class TestClass implements IntefaceA, IntefaceB {
public static void main(String[] args) {
for (RepeatableAnnotation a : TestClass.class.getAnnotation(RepeatableAnnotations.class).value()) {
System.out.print(a.value());
}
}
}
我会 希望 输出为 ABCD
但它是 "just" CD
(即 @Inherited
正在工作完全像之前 Java 8).
有谁知道在 Java 8 的 @Repeatable
注释的情况下是否有充分的理由不删除关于接口和方法的 @Inherited
限制?
是否有任何解决方法可以实现上述类型层次结构的 ABCD
输出? (除了使用反射扫描注解的超级接口...)
请回忆@Inherited
的文档:
If an Inherited meta-annotation is present on an annotation type declaration, and the user queries the annotation type on a class declaration, and the class declaration has no annotation for this type, then the class's superclass will automatically be queried for the annotation type.
换句话说,@Inherited
从未打算成为在类型层次结构上收集多个注释的功能。相反,您将获得具有显式注释的最具体类型的注释。
换句话说,如果您将声明更改为
@RepeatableAnnotation("FOO") @RepeatableAnnotation("BAR") class Base {}
@RepeatableAnnotation("C") @RepeatableAnnotation("D")
public class TestClass extends Base implements IntefaceA, IntefaceB {
不会改变结果; Base
的 FOO
和 BAR
未被 TestClass
继承,因为它具有显式注释值 C
和 D
.
将其扩展到 interface
层次结构会很尴尬,因为多重继承以及超级接口可能会变成另一个超级接口的子接口,因此要找到最具体的一个不是微不足道的。这与超类层次结构的线性搜索有很大不同。
您可能会遇到存在多个不相关的注释 interface
的情况,但不清楚为什么要通过将它们合并为一个重复注释来解决这种歧义。这与所有其他情况下的行为不一致。
请注意,answer you have linked 有点奇怪,因为它显示使用方法注释的代码,但方法注释永远不会被继承,无论您是否指定 @Inherited
(审计工具应生成当您将 @Target(ElementType.METHOD)
与 @Inherited
结合使用时发出警告,恕我直言)。 @Inherited
仅与类型注释相关。
在 Java 中标记为 @Inherited
的注释仅在注释 classes:
Note that this meta-annotation type has no effect if the annotated type is used to annotate anything other than a class. Note also that this meta-annotation only causes annotations to be inherited from superclasses; annotations on implemented interfaces have no effect.
因此,使用 @Inherited
注释进行注释的接口或方法不会导致实现 classes/methods 也使用该注释进行注释。原因很可能是,如果 class 层次结构中有多个注释,如 here.
现在Java8引入了新的注解@Repeatable
。我认为取消上述对标记为 @Inherited
和 @Repeatable
的注释的限制是很自然的,因为编译器随后应该能够将冲突的注释添加到 @Repeatable
注释。
给定以下示例:
import java.lang.annotation.Inherited;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@interface RepeatableAnnotations {
RepeatableAnnotation[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@Repeatable(RepeatableAnnotations.class)
@interface RepeatableAnnotation {
String value();
}
@RepeatableAnnotation("A")
interface IntefaceA {}
@RepeatableAnnotation("B")
interface IntefaceB {}
@RepeatableAnnotation("C")
@RepeatableAnnotation("D")
public class TestClass implements IntefaceA, IntefaceB {
public static void main(String[] args) {
for (RepeatableAnnotation a : TestClass.class.getAnnotation(RepeatableAnnotations.class).value()) {
System.out.print(a.value());
}
}
}
我会 希望 输出为 ABCD
但它是 "just" CD
(即 @Inherited
正在工作完全像之前 Java 8).
有谁知道在 Java 8 的 @Repeatable
注释的情况下是否有充分的理由不删除关于接口和方法的 @Inherited
限制?
是否有任何解决方法可以实现上述类型层次结构的 ABCD
输出? (除了使用反射扫描注解的超级接口...)
请回忆@Inherited
的文档:
If an Inherited meta-annotation is present on an annotation type declaration, and the user queries the annotation type on a class declaration, and the class declaration has no annotation for this type, then the class's superclass will automatically be queried for the annotation type.
换句话说,@Inherited
从未打算成为在类型层次结构上收集多个注释的功能。相反,您将获得具有显式注释的最具体类型的注释。
换句话说,如果您将声明更改为
@RepeatableAnnotation("FOO") @RepeatableAnnotation("BAR") class Base {}
@RepeatableAnnotation("C") @RepeatableAnnotation("D")
public class TestClass extends Base implements IntefaceA, IntefaceB {
不会改变结果; Base
的 FOO
和 BAR
未被 TestClass
继承,因为它具有显式注释值 C
和 D
.
将其扩展到 interface
层次结构会很尴尬,因为多重继承以及超级接口可能会变成另一个超级接口的子接口,因此要找到最具体的一个不是微不足道的。这与超类层次结构的线性搜索有很大不同。
您可能会遇到存在多个不相关的注释 interface
的情况,但不清楚为什么要通过将它们合并为一个重复注释来解决这种歧义。这与所有其他情况下的行为不一致。
请注意,answer you have linked 有点奇怪,因为它显示使用方法注释的代码,但方法注释永远不会被继承,无论您是否指定 @Inherited
(审计工具应生成当您将 @Target(ElementType.METHOD)
与 @Inherited
结合使用时发出警告,恕我直言)。 @Inherited
仅与类型注释相关。