为什么Java类不会继承实现的接口的注解?

121
我正在使用一个依赖注入框架(Guice的AOP来拦截特定的方法调用)。我的类实现了一个接口,我想注释这个接口方法,以便框架可以选择正确的方法。即使注释类型被注释为Inherited注释,实现类也不会像在Inherited的Java文档中所述那样继承注释:

请注意,这个元注释只会导致注释从超类继承;在实现的接口上的注释没有任何效果。

这种情况的原因是什么?在运行时了解对象类实现的所有接口并不是一件很困难的事情,所以这个决定背后一定有一个很好的理由。
2个回答

140
我认为原因是,否则会出现多重继承的问题。 示例:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Inherited
public @interface Baz { String value(); }

public interface Foo{
    @Baz("baz") void doStuff();
}

public interface Bar{
    @Baz("phleem") void doStuff();
}

public class Flipp{
    @Baz("flopp") public void doStuff(){}
}

public class MyClass extends Flipp implements Foo, Bar{}

如果我这样做:

MyClass.class.getMethod("doStuff").getAnnotation(Baz.class).value()

结果会是什么?'baz'、'phleem' 还是 'flopp'?


因此,在接口上的注释很少有用。


9
只有当你使用支持注解的框架时,接口上的注解才有用。顺便说一句,在这个例子中,getAnnotation() 返回 null ;) - Peter Lawrey
6
我不知道,人们。在这种情况下(如果没有错别字),我会像两个接口声明不同值的常量一样,期望出现类似于“字段值不明确”的编译器错误。我知道这不是一个字段,但是注解值在编译时全部解析完毕,对吧?我们在这里缺少的功能在许多情况下都非常有用。顺便说一句,很抱歉重新激活了一个旧帖子 :)。 - Petr Janeček
7
@Slanec,看一下Spring源代码中是如何解决这些问题的。请参考AnnotationUtils.findAnnotation(method, annotationType) - Sean Patrick Floyd
1
应该是 getAnnotation(Baz.class) 吗? - wchargin
2
@WChargin 是的,只是花了两年时间才有人发现那个错别字 :-) - Sean Patrick Floyd
显示剩余3条评论

38

根据 @Inherited 的Javadoc:

指示注解类型自动继承。如果在注解类型声明上存在Inherited元注释,并且用户在类声明上查询注解类型,而该类声明没有此类型的注解,则将自动查询类的超类以获取注解类型。这个过程将重复进行,直到找到该类型的注解或达到类层次结构(Object)的顶部。如果没有超类具有此类型的注解,则查询将指示所讨论的类没有此类注解。请注意,如果使用注释类型对除类之外的任何内容进行注释,则此元注释类型无效。还要注意,此元注释仅导致从超类继承注释;实现接口上的注释无效。

另一方面,JSR 305验证器会执行某种继承查找。如果您有一个类层次结构:

//Person.java
@Nonnull
 public Integer getAge() {...}

//Student.java (inherits from Person)
@Min(5)
public Integer getAge() {...}

那么对于Student.getAge()成功的验证是@Nonnull @Min(5)@Nonnull没有@Inherited元注释


4
这个应该被选为最佳答案。 - Andrzej Purtak
4
你的例子与你的答案相矛盾,答案说 @Inherited 对除类以外的任何东西都没有影响。 - Oleg Mikheev
2
@Inherited 只有在你将注解用于类时才会起作用。 - Carlos Parker
1
回答一下关于接口上注解的问题,怎么样? - cdalxndr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接