在Java中,标记为 @Inherited 的注释仅在注释类时起作用:

请注意,如果带注释,则此元注释类型无效
type用于注释除类之外的任何内容。另请注意
此元批注仅导致从中继承批注
超类已实现的接口上的注释无效。

因此,使用@Inherited注释进行注释的接口或方法不会导致实现类/方法也要使用该注释进行注释。原因很可能是,如果在类层次结构中有多个批注(如here所述),则编译器将不知道要选择哪个批注。

现在,Java 8引入了新的注释 @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,但是它只是“CD”(即@Inherited的工作方式与Java 8之前的版本完全相同)。

有谁知道在Java 8的@Inherited注释的情况下是否有充分的理由不删除关于接口和方法的@Repeatable限制?

是否有解决上述类型层次结构的ABCD输出的解决方法? (除了使用反射来扫描超级接口以查看注释...)

最佳答案

请回顾 @Inherited 的文档:

如果注释类型声明中存在继承的元注释,并且用户在类声明上查询了注释类型,并且该类声明没有该类型的注释,则将自动查询该类的超类以获取注释类型。

换句话说,@Inherited从未打算成为用于在类型层次结构上收集多个注释的功能。相反,您将获得具有显式注释的最特定类型的注释。

换句话说,如果您将声明更改为

@RepeatableAnnotation("FOO") @RepeatableAnnotation("BAR") class Base {}

@RepeatableAnnotation("C") @RepeatableAnnotation("D")
public class TestClass extends Base implements IntefaceA, IntefaceB {

它不会改变结果; FOO不继承BARBaseTestClass,因为它具有显式注释值CD

由于多重继承以及一个超级接口可能成为另一个超级接口的子接口的事实,因此将其扩展到interface层次结构将很困难。这与超类层次结构的线性搜索有很大不同。

您可能会遇到存在多个不相关的带注释的interface的情况,但尚不清楚为什么应通过将它们合并为一个重复的注释来解决这种歧义。这不会与所有其他情况下的行为保持一致。

请注意,answer you have linked有点奇怪,因为它使用方法注释显示代码,但无论您是否指定@Inherited,方法注释都不会继承(审计工具应在将@Target(ElementType.METHOD)@Inherited,imho结合使用时生成警告)。 @Inherited仅与类型注释有关。

07-26 03:57