Answers:
关于未采用这种方式进行设计的原因,您可以在JSR 175设计常见问题解答中找到答案,其中说:
您为什么不支持注释子类型化(一种注释类型扩展了另一种注释类型)?
它使注释类型系统变得复杂,并使编写“特定工具”变得更加困难。
…
“特定工具” —查询任意外部程序的已知注释类型的程序。例如,存根生成器就属于此类。这些程序将读取带注释的类,而不将其加载到虚拟机中,但是将加载注释接口。
所以,是的,我想,原因只是KISS。无论如何,似乎这个问题(以及许多其他问题)已作为JSR 308的一部分被研究,您甚至可以找到带有Mathias Ricken已经开发的此功能的替代编译器。
可扩展的注释将有效地增加指定和维护另一种类型系统的负担。而且这将是一个非常独特的类型系统,因此您不能简单地应用OO类型范例。
当您将多态性和继承引入注解时,请仔细考虑所有问题(例如,当子注解更改元注解规范(例如保留)时会发生什么?
对于所有用例,所有这些增加的复杂性?
您想知道给定的注释是否属于类别吗?
试试这个:
@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
String category();
}
@Category(category="validator")
public @interface MyFooBarValidator {
}
如您所见,您可以使用提供的功能轻松对批注进行分组和分类,而不会造成不必要的麻烦。
因此,KISS是不向Java语言引入元类型类型系统的原因。
[ps编辑]
考虑到开放式元注释,我仅将String用于演示。对于您自己的给定项目,您显然可以使用类别类型的枚举并为给定批注指定多个类别(“多重继承”)。请注意,这些值完全是伪造的,仅用于演示目的:
@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
AnnotationCategory[] category();
}
public enum AnnotationCategory {
GENERAL,
SEMANTICS,
VALIDATION,
ETC
}
@Category(category={AnnotationCategory.GENERAL, AnnotationCategory.SEMANTICS})
public @interface FooBarAnnotation {
}
@Target(ElementType.ANNOTATION_TYPE) @Retention(RetentionPolicy.RUNTIME) @interface C {}; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @C public @interface F {} class a{ @F public void S() {} } @Test public void blahTest() throws NoSuchMethodException { Method m = a.class.getMethod("S"); System.out.println(m.isAnnotationPresent(C.class)); }
从某种意义上说,您已经有了Annotations-meta Annotations。如果使用元信息为注释添加注释,则在许多方面都等同于扩展其他接口。注释是接口,因此多态性实际上并没有发挥作用,并且由于它们本质上是静态的,因此无法进行运行时动态调度。
在您的验证器示例中,您可以仅在注释上获取带注释的类型,并查看其是否具有验证器元注释。
我可以看到的唯一用例是,继承是有帮助的,如果您希望能够通过超类型获取注释,但这会增加一堆复杂性,因为给定的方法或类型上可能有两个这样的注释,意味着必须返回一个数组,而不仅仅是一个对象。
因此,我认为最终的答案是用例是深奥的,使更多的标准用例变得复杂,使其不值得。
Java注释支持的设计者对Java社区造成了许多“简化”。
没有注释子类型会使许多复杂的注释变得不必要地丑陋。一个人不能简单地在批注中拥有可以容纳三件事之一的属性。一个需要具有三个单独的属性,这会使开发人员感到困惑,并且需要运行时验证以确保仅使用这三个属性之一。
每个站点只有一个给定类型的注释。这导致了完全不必要的集合注释模式。@Validation和@ Validations,@ Image和@Images等。
第二个正在Java 8中进行补救,但为时已晚。基于Java 5可能编写的许多框架,现在这些API缺陷将保留很长时间。
我回答这个问题可能晚了三年,但是我发现它很有趣,因为我发现自己处在同一位置。这是我的看法。您可以将注释查看为枚举。他们提供一种单向的信息-使用它或丢失它。
我遇到一种情况,想在Web应用程序中模拟GET,POST,PUT和DELETE。我非常想拥有一个名为“ HTTP_METHOD”的“超级”注释。后来我突然意识到这没关系。好吧,我不得不使用HTML表单中的隐藏字段来标识DELETE和PUT(因为POST和GET仍然可用)。
在服务器端,我寻找了一个名为“ _method”的隐藏请求参数。如果该值为PUT或DELETE,则它将覆盖关联的HTTP请求方法。话虽如此,我是否需要扩展注释以完成工作并不重要。所有注释看起来都一样,但是在服务器端它们的处理方式有所不同。
因此,在您的情况下,请放下脚步以扩展注释。将它们视为“标记”。它们“代表”某些信息,而不一定“操纵”某些信息。
java.lang.annotation.Annotation
,即instanceof
,尽管没有显式声明这一事实,但任何注释都可以。