为注释的字段设置默认空值时出错

rip*_*234 69 java annotations default

为什么我会收到错误"属性值必须保持不变".是不是不变???

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SomeInterface {
    Class<? extends Foo> bar() default null;// this doesn't compile
}
Run Code Online (Sandbox Code Playgroud)

Yis*_*hai 57

我不知道为什么,但JLS非常明确:

 Discussion

 Note that null is not a legal element value for any element type. 
Run Code Online (Sandbox Code Playgroud)

而默认元素的定义是:

     DefaultValue:
         default ElementValue
Run Code Online (Sandbox Code Playgroud)

不幸的是,当你不符合语言规范时,我一直发现新的语言功能(Enums和now Annotations)有非常无用的编译错误信息.

编辑:有点googleing 在JSR-308中发现以下内容,他们认为在这种情况下允许空值:

我们注意到该提案可能存在一些异议.

该提案没有做出任何以前不可能的事情.

程序员定义的特殊值提供了比null更好的文档,这可能意味着"无","未初始化",null本身等.

该提案更容易出错.忘记检查null比忘记检查显式值要容易得多.

该提案可能使标准成语更加冗长.目前只有注释的用户需要检查其特殊值.使用该提议,许多处理注释的工具必须检查字段的值是否为空,以免它们抛出空指针异常.

我认为只有最后两点与"为什么不首先这样做"有关.最后一点肯定会带来一个好点 - 注释处理器永远不必担心它们会在注释值上获得null.我倾向于认为注释处理器和其他类似框架代码的工作更多的是必须进行这种检查以使开发人员代码更清晰而不是相反,但它肯定会很难证明改变它是正确的.


Log*_*phy 57

试试这个

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SomeInterface {
    Class bar() default void.class;
}
Run Code Online (Sandbox Code Playgroud)

它不需要新的类,它已经是Java中的关键字,没有任何意义.

  • 我喜欢.唯一的问题 - 在原始问题的上下文中 - 这个答案不支持类型参数:`Class <?extends Foo> bar()默认void.null`不编译. (8认同)
  • 通常不能应用void.class:public @interface NoNullDefault {String value()default void.class; } (3认同)

ska*_*man 50

虽然JLS在这方面非常模糊,但这似乎是非法的.

我破坏了我的记忆,试着想到那里有一个注释的Class属性的现有注释,并记住了JAXB API中的这个注释:

@Retention(RUNTIME) @Target({PACKAGE,FIELD,METHOD,TYPE,PARAMETER})        
public @interface XmlJavaTypeAdapter {
    Class type() default DEFAULT.class;

    static final class DEFAULT {}    
}
Run Code Online (Sandbox Code Playgroud)

您可以看到他们如何定义一个虚拟静态类来保存等效的null.

不愉快.

  • 对于字符串字段,您必须求助于[魔术字符串](http://en.wikipedia.org/wiki/Magic_string).显然,众所周知的反模式比现在熟知的语言功能更好. (7认同)
  • 是的,我们做了类似的事情(我们只使用Foo.class作为默认值).吮吸. (3认同)
  • @TimYates它让我看到人们在null可用且普遍理解时定义他们自己的"无价值"哨兵值.现在这是语言本身所要求的吗?!幸运的是,您可以将"魔术字符串"定义为公共常量.它仍然不理想,但至少寻找你的注释的代码可以引用常量而不是在任何地方使用文字. (3认同)

She*_*ari 9

似乎还有另外一种方法.

我也不喜欢这样,但它可能会奏效.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SomeInterface {
    Class<? extends Foo>[] bar() default {};
}
Run Code Online (Sandbox Code Playgroud)

所以基本上你创建一个空数组.这似乎允许默认值.