为什么不能在Java中扩展注释?

时间:2009-10-26 10:31:23

标签: java inheritance annotations

我不明白为什么Java注释中没有继承,就像Java类一样。我认为这将非常有用。

例如:我想知道给定的注释是否是验证器。通过继承,我可以反复地浏览超类以了解此注释是否扩展了ValidatorAnnotation。否则,我怎么能实现这个目标呢?

那么,任何人都可以给我这个设计决定的理由吗?

8 个答案:

答案 0 :(得分:158)

关于它没有这样设计的原因,您可以在JSR 175设计常见问题解答中找到答案,其中包含:

  

为什么不支持注释子类型(一个注释类型扩展另一个注释类型)?

     

它使注释类型复杂化   系统,并使其更多   很难写“特定工具”。

     

...

     

“特定工具” - 查询的程序   已知的任意注释类型   外部程序。短管发电机,   例如,属于这一类。   这些程序将读取注释   没有加载它们的类   虚拟机,但会加载   注释接口。

所以,是的,我猜,原因是它只是KISS。无论如何,似乎这个问题(以及许多其他问题)正在作为JSR 308的一部分进行研究,你甚至可以找到一个已由Mathias Ricken开发的具有此功能的替代编译器。

答案 1 :(得分:66)

可扩展注释会有效地增加指定和维护另一个类型系统的负担。这将是一个相当独特的类型系统,因此您不能简单地应用OO类型范例。

在向注释引入多态性和继承时考虑所有问题(例如,当子注释更改元注释规范(例如保留)时会发生什么?)

所有这些增加了用例的复杂性?

您想知道给定的注释是否属于某个类别吗?

试试这个:

@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
    String category();
}

@Category(category="validator")
public @interface MyFooBarValidator {

}

正如您所看到的,您可以使用提供的设施轻松地对注释进行分组和分类,而不会造成过度的痛苦。

因此,KISS是不向Java语言引入元类型系统的原因。

[P.S。编辑]

我将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 {

}

答案 2 :(得分:11)

从某种意义上说,你已经拥有了Annotations - meta Annotations。如果使用元信息注释注释,则在许多方面等同于扩展其他接口。注释是接口,因此多态性并没有真正发挥作用,并且因为它们本质上是静态的,所以不能进行运行时动态调度。

在验证器示例中,您可以只在注释上获取带注释的类型,并查看它是否具有验证器元注释。

唯一可以看到继承有用的用例是,如果你希望能够通过超类型获取注释,但这会增加一大堆复杂性,因为给定的方法或类型可能有两个这样的注释在它上面,意味着必须返回一个数组,而不仅仅是一个对象。

所以我认为最终的答案是用例是深奥的,并且使更多标准用例复杂化,使其不值得。

答案 3 :(得分:5)

Java注释支持的设计者进行了许多“简化”,损害了Java社区。

  1. 没有注释子类型会使许多复杂的注释变得不必要地丑陋。人们不能简单地在注释中具有可以容纳三件事之一的属性。一个人需要有三个独立的属性,这会使开发人员感到困惑并需要运行时验证,以确保只使用三者中的一个。

  2. 每个网站只有一个给定类型的注释。这导致了完全不必要的集合注释模式。 @Validation和@Validations,@ Image和@Images等

  3. 第二个是在Java 8中修复,但为时已晚。许多框架都是基于Java 5中可能的内容编写的,现在这些API疣在这里停留了很长时间。

答案 4 :(得分:2)

我能想到的一件事是有多个注释的可能性。因此,您可以在同一位置添加验证器和更具体的注释。但我可能会弄错:)

答案 5 :(得分:2)

从来没有想过,但......似乎你是对的,注释继承工具没有问题(至少我没有看到它的问题)。

关于'验证器'注释的示例 - 您可以利用'元注释'方法。即您将特定的元注释应用于整个注释界面。

答案 6 :(得分:2)

在回答这个问题时我可能会迟到三年,但我发现它很有趣,因为我发现自己处于同一个位置。这是我的看法。您可以将注释视为枚举。它们提供单向信息 - 使用或丢失信息。

我有一种情况,我想在网络应用程序中模拟GET,POST,PUT和DELETE。我非常想要一个名为“HTTP_METHOD”的“超级”注释。后来我突然意识到这没关系。好吧,我不得不使用HTML表单中的隐藏字段来识别DELETE和PUT(因为POST和GET都是可用的)。

在服务器端,我寻找一个名为“_method”的隐藏请求参数。如果值为PUT或DELETE,则它会覆盖关联的HTTP请求方法。话虽如此,我是否需要扩展注释以完成工作并不重要。所有注释看起来都一样,但在服务器端对它们的处理方式不同。

所以在你的情况下,放弃痒以扩展注释。将它们视为“标记”。它们“代表”某些信息,而不一定“操纵”某些信息。

答案 7 :(得分:1)

我遇到同样的问题。不,你不能。我确实“训练”自己在注释中写入属性以尊重某些标准,因此在获得注释之外,您可以“嗅探”它具有的属性是什么类型的注释。