Java注解成员可以使用哪些类型?

303

今天我想按照这份文档创建我的第一个注解接口,但是我得到了以下编译器错误信息:

Invalid type for annotation member":
public @interface MyAnnotation {
    Object myParameter;
    ^^^^^^
}
显然,Object不能用作注解成员的类型。不幸的是,我没有找到任何关于一般可以使用哪些类型的信息。
通过试错法,我发现了以下内容:
  • String → 有效
  • int → 有效
  • Integer → 无效(令人惊讶)
  • String[] → 有效(令人惊讶)
  • Object → 无效
也许有人可以阐明实际允许使用哪些类型以及原因。

可能会因注释而不同 - 请展示您试图编写的代码。 - djna
2
已添加到问题中。但我认为它不会有所不同。 - Daniel Rikowski
4个回答

397

这是由JLS第9.6.1节规定的。注解成员类型必须是以下之一:

  • 基本类型
  • 字符串类型
  • 枚举类型
  • 另一个注解类型
  • Class类型
  • 上述任何类型的数组

它似乎很受限制,但毫无疑问有理由这样做。

还要注意,以上规则隐式禁止了多维数组(例如String[][])。

此答案所述,不允许使用Class的数组。


46
如何找到那些页面或文件?我发誓在向 StackOverlow 提问之前每次都会使用 Google,而且在很多关于 Java 的问题上,有人会贴出一个链接指向 JSL,该链接正好回答了我的问题。为什么我无法通过 Google 找到这些页面呢? - Daniel Rikowski
13
JLS不太适合在谷歌上搜索,你只需要知道它的存在即可。 - skaffman
15
以上列表中缺少的是“注释”。您可以有一个包含另一个注释或另一个注释数组的注释。 - Matt
2
请注意,“Class”在这里是指字面上的_java.lang.Class_类,而不是所有类。 - Kajzer
1
@skaffman:“如本答案所述,不允许使用类数组。”我已经阅读了链接,但我看不出为什么不允许使用Class[],您能否澄清一下? - Revin
显示剩余6条评论

41

不要忘记注释本身可以成为注释定义的一部分。这允许一些简单的注释嵌套 - 在您希望一个注释出现多次的情况下非常方便。

例如:

@ComplexAnnotation({
    @SimpleAnnotation(a="...", b=3),
    @SimpleAnnotation(a="...", b=3),
    @SimpleAnnotation(a="...", b=3)
})
public Object foo() {...}

其中SimpleAnnotation

@Target(ElementType.METHOD)
public @interface SimpleAnnotation {
    public String a();
    public int b();
)

ComplexAnnotation

@Target(ElementType.METHOD)
public @interface ComplexAnnotation {
    public SimpleAnnotation[] value() default {};
)

示例来源:http://web.archive.org/web/20131216093805/https://blogs.oracle.com/toddfast/entry/creating_nested_complex_java_annotations

(原始URL:https://blogs.oracle.com/toddfast/entry/creating_nested_complex_java_annotations)


8
自从Java 8引入了@Repeatable,这个就不再需要了。 - Mordechai
严格来说,“@Repeatable”意味着编译器可以为您构建它。 - Donal Fellows

15

注释概念非常适合我的项目设计,但直到我发现在注释中无法使用复杂数据类型。我通过使用我想要实例化的类的类而不是该类的已实例化对象来解决了这个问题。虽然不完美,但 Java 很少会做到完美。

@interface Decorated { Class<? extends PropertyDecorator> decorator() }

interface PropertyDecorator { String decorate(String value) }

class TitleCaseDecorator implements PropertyDecorator {
    String decorate(String value)
}

class Person {
    @Decorated(decorator = TitleCaseDecorator.class)
    String name
}

1
你在@interface Decorated中使用了什么目标类型?我尝试在我的项目中使用这个模式,一切都编译通过了,但在运行时我得到了一个大而臃肿的空指针异常,它指向了"String name"(在我的情况下是:List<SomeStuff> myList(试图用一个需要处理某些东西的列表来装饰一个通用处理器))。 - niken

2
根据Oracle的说法,注释元素的有效类型为:
1. Primitives (byte, char, int, long float, double)
2. Enums
3. Class (Think generics here Class <?>, Class<? extends/super T>>)
4. String
5. Array of the above (array[] of primitives, enums, String, or Class)
5. Another annotation.

一个需要注意的加分项是,所有元素本质上都被视为公共和抽象的。
因此,
 static final variable(s) allowed as well.

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