为什么不能在 Java 中扩展注解?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1624084/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is it not possible to extend annotations in Java?
提问by sinuhepop
I don't understand why there is no inheritance in Java annotations, just as Java classes. I think it would be very useful.
我不明白为什么Java注释中没有继承,就像Java类一样。我认为这将非常有用。
For example: I want to know if a given annotation is a validator. With inheritance, I could reflexively navigate through superclasses to know if this annotation extends a ValidatorAnnotation
. Otherwise, how can I achieve this?
例如:我想知道给定的注释是否是验证器。通过继承,我可以反射性地浏览超类以了解此注释是否扩展了ValidatorAnnotation
. 否则,我怎么能做到这一点?
So, can anyone give me a reason for this design decision?
那么,谁能给我一个做出这个设计决定的理由?
采纳答案by pedromarce
About the reason why it wasn't designed that way you can find the answer in the JSR 175Design FAQ, where it says:
关于它不是这样设计的原因,您可以在JSR 175设计常见问题解答中找到答案,它说:
Why don't you support annotation subtyping (where one annotation type extends another)?
It complicates the annotation type system, and makes it much more difficult to write “Specific Tools”.
…
“Specific Tools” — Programs that query known annotation types of arbitrary external programs. Stub generators, for example, fall into this category. These programs will read annotated classes without loading them into the virtual machine, but will load annotation interfaces.
为什么不支持注释子类型(一种注释类型扩展另一种注释类型)?
它使注释类型系统复杂化,并使编写“特定工具”变得更加困难。
…
“特定工具”——查询任意外部程序的已知注释类型的程序。例如,存根生成器就属于这一类。这些程序将读取带注释的类而不将它们加载到虚拟机中,但会加载注释接口。
So, yes I guess, the reason is it just KISS. Anyway, it seems this issue (along with many others) are being looked into as part of JSR 308, and you can even find an alternative compiler with this functionality already developed by Mathias Ricken.
所以,是的,我想,原因是它只是 KISS。无论如何,似乎这个问题(以及许多其他问题)正在作为JSR 308 的一部分进行研究,您甚至可以找到具有此功能的替代编译器,该编译器已经由Mathias Ricken开发。
回答by ante.sabo
the same problem I have. No, you can't. I did 'disciplined' myself to write properties in annotations to respect some standards, so outside when you get annotation you can 'sniff' what kind od annotation it is by properties it has.
我有同样的问题。不,你不能。我确实“自律”自己在注释中编写属性以遵守某些标准,因此当您获得注释时,您可以“嗅探”它具有的属性是什么类型的注释。
回答by Janusz
One thing I could think of is the possibility to have multiple annotations. So you could add validator and a more specific annotation at the same place. But I could be mistaken :)
我能想到的一件事是有多个注释的可能性。因此,您可以在同一位置添加验证器和更具体的注释。但我可能会误会:)
回答by denis.zhdanov
Never thought about that but... seems that you're right, there is no problem with annotations inheritance facility (at least I don't see the problem with it).
从来没有想过,但是......似乎你是对的,注释继承工具没有问题(至少我没有看到它的问题)。
About your example with 'validator'annotation - you can exploit 'meta-annotation'approach then. I.e. you apply particular meta-annotation to the whole annotation interface.
关于带有“验证器”注释的示例- 然后您可以利用“元注释”方法。即您将特定的元注释应用于整个注释界面。
回答by alphazero
Extensible annotations would effectively add the burden of specifying and maintaing another type system. And this would be a fairly unique type system, so you could not simply apply an OO type paradigm.
可扩展的注释会有效地增加指定和维护另一个类型系统的负担。这将是一个相当独特的类型系统,因此您不能简单地应用 OO 类型范例。
Think through all the issues when you introduce polymorphism and inheritance to an annotation (e.g. what happens when sub-annotation changes meta-annotation specs such as retention?)
将多态和继承引入注解时,请仔细考虑所有问题(例如,当子注解更改元注解规范(例如保留)时会发生什么?)
And all this added complexity for what use-case?
所有这些都为什么用例增加了复杂性?
You want to know if a given annotation belongs to a category?
您想知道给定的注释是否属于某个类别?
Try this:
尝试这个:
@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
String category();
}
@Category(category="validator")
public @interface MyFooBarValidator {
}
As you can see, you can easily group and categorize annotations without undue pain using the provided facilities.
如您所见,您可以使用提供的工具轻松地对注释进行分组和分类,而不会造成不必要的痛苦。
So, KISSis the reason for not introducing a meta-type type system to the Java language.
因此,KISS是不向 Java 语言引入元类型类型系统的原因。
[p.s. edit]
[ps编辑]
I used the String simply for demonstration and in view of an open ended meta annotation. For your own given project, you obviously can use an enum of category types and specify multiple categories ("multiple inheritance") to a given annotation. Do note that the values are entirely bogus and for demonstration purposes only:
我使用 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 {
}
回答by Yishai
In a sense you already have it with Annotations - meta Annotations. If you annotate an annotation with meta information, that is in many ways equivalent to extending an additional interface. Annotations are interfaces, so polymorphism doesn't really come into play, and since they are static in nature, there can be no runtime dynamic dispatching.
从某种意义上说,您已经拥有注释 - 元注释。如果您使用元信息对注解进行注解,这在许多方面等同于扩展附加接口。注释是接口,所以多态性并没有真正发挥作用,而且由于它们本质上是静态的,因此不可能有运行时动态调度。
In your validator example, you could just on the annotation get the annotated type and see if it has a validator meta-annotation.
在您的验证器示例中,您可以仅在注释上获取带注释的类型并查看它是否具有验证器元注释。
The only use case I could see that inheritance would help is if you wanted to be able to get the annotation by super type, but that would add a whole bunch of complexity, because a given method or type may have two such annotations on it, meaning that an array would have to be returned instead of just a single object.
我认为继承会有所帮助的唯一用例是,如果您希望能够通过超类型获取注释,但这会增加一大堆复杂性,因为给定的方法或类型可能有两个这样的注释,这意味着必须返回一个数组,而不仅仅是一个对象。
So I think the ultimate answer is that the use cases are esoteric and complicate more standard use cases making it not worth it.
所以我认为最终的答案是用例是深奥的,并且使更标准的用例复杂化,使其不值得。
回答by mainas
I might be three years late in responding to this question, but I found it interesting because I found myself in the same spot. Here's my take on it. You can view annotations as Enums. They provide a one-way kind of information - use it or lose it.
我可能在回答这个问题时晚了三年,但我觉得这很有趣,因为我发现自己处于同一个位置。这是我的看法。您可以将注释视为枚举。它们提供了一种单向的信息——使用它或丢失它。
I had a situation where I wanted to simulate GET, POST, PUT and DELETE in a web-app. I so badly wanted to have a "super" annotation that was called "HTTP_METHOD". It later on dawned on me that it didn't matter. Well, I had to settle with using a hidden field in the HTML form to identify DELETE and PUT (because POST and GET were available anyway).
我有一种情况,我想在 Web 应用程序中模拟 GET、POST、PUT 和 DELETE。我非常想拥有一个名为“HTTP_METHOD”的“超级”注释。后来我才明白这并不重要。好吧,我不得不在 HTML 表单中使用隐藏字段来识别 DELETE 和 PUT(因为 POST 和 GET 无论如何都可用)。
On the server-side, I looked out for a hidden request parameter with the name, "_method". If the value was PUT or DELETE, then it overrode the associated HTTP request method. Having said that, it didn't matter whether or not I needed to extend an annotation to get the work done. All the annotations looked the same, but they were treated differently on the server side.
在服务器端,我寻找了一个名为“_method”的隐藏请求参数。如果该值为 PUT 或 DELETE,则它会覆盖关联的 HTTP 请求方法。话虽如此,我是否需要扩展注释来完成工作并不重要。所有的注释看起来都一样,但在服务器端的处理方式不同。
So in your case, drop the itch to extend annotations. Treat them as 'markers'. They "represent" some information, and not necessarily "manipulate" some information.
所以在你的情况下,放弃扩展注释的渴望。将它们视为“标记”。它们“代表”一些信息,而不一定“操纵”一些信息。
回答by Konstantin Komissarchik
The designers of Java annotation support made a number of "simplifications" to the detriment of the Java community.
Java 注释支持的设计者进行了许多对 Java 社区不利的“简化”。
No annotations subtypes makes many complex annotations unnecessarily ugly. One cannot simply have an attribute within an annotations that can hold one of three things. One needs to have three separate attributes, which confuses developers and requires runtime validation to ensure that only one of the three is used.
Only one annotation of a given type per site. This has lead to the completely unnecessary collection annotation pattern. @Validation and @Validations, @Image and @Images, etc.
没有注释子类型会使许多复杂的注释变得不必要地丑陋。不能简单地在注释中拥有一个可以包含三件事之一的属性。一个需要拥有三个独立的属性,这会让开发人员感到困惑,并且需要运行时验证以确保仅使用三个中的一个。
每个站点只有一个给定类型的注释。这导致了完全不必要的集合注释模式。@Validation 和@Validations、@Image 和@Images 等。
The second one is being remedied in Java 8, but its too late. Many frameworks have been written based on what was possible in Java 5 and now these API warts are here to stay for a good long time.
第二个正在 Java 8 中修复,但为时已晚。许多框架是基于 Java 5 中的可能性编写的,现在这些 API 问题已经存在很长时间了。