附加到新对象的Java Annotation?

时间:2017-03-03 17:31:49

标签: java object annotations

是否可以将注释附加到新对象?

假设我们有一个简单的房子对象House house = new House () 和注释@Large@Spooky

我的想法是设置一个切换声明,因此标记为@Spooky的房屋与标有@Large的房屋不同。

@Spooky
House house = new House();

System.out.println(house.getClass().getAnnotations().length);

显然,我的新房屋对象上没有注释length == 0

为什么?

1 个答案:

答案 0 :(得分:2)

一般

您无法注释对象(仅在运行时存在)。您可以注释声明,或者自Java 8以来,类型用法(已在编译时存在)。

请参阅The Java™ Tutorials, Annotations, Annotations Basics

  

可以使用注释

     

注释可以应用于声明:类,字段,方法和其他程序元素的声明。 [...]   从Java SE 8版本开始,注释也可以应用于类型的使用

The Java™ Tutorials, Annotations, Type Annotations [...]

  

在Java SE 8发布之前,注释只能应用于声明。从Java SE 8版本开始,注释也可以应用于任何类型的使用。这意味着注释可以在任何使用类型的地方使用。一些例子使用的类是类实例创建表达式(new),强制转换,implements子句和throws子句。这种形式的注释称为类型注释[...]。

和可靠的最终来源The Java® Language Specification, 9.6.4. Predefined Annotation Types

  

<强> 9.6.4.1。 @target

     

注释类型可能适用于声明上下文,其中注释适用于声明,类型上下文注释适用于声明和表达式中使用的类型。

[由我强调。]

Anwer to your question

正如@ M.Prokhorov在他对你的问题的评论中提到的那样,你没有注释你的House类,而是house的局部变量声明,即类型House。< / p>

另见Java Annotations Tutorial

  

注释放置

     

您可以将Java [声明]注释放在类,接口,方法,方法参数,字段和局部变量之上。   [...]

     

创建自己的注释

     

[...]

     

@Retention

     

[...]

@Retention(RetentionPolicy.RUNTIME)
     

这是向Java编译器和JVM发出的信号,表明注释应该通过运行时的反射来提供

     

[...]

     

RetentionPolicy.CLASS表示注释存储在.class文件中,但在运行时不可用。如果您未指定任何保留策略,则这是默认保留策略。

[由我强调。]

这意味着您必须使用以下内容声明Spooky注释:

@Retention( RetentionPolicy.RUNTIME )
public @interface Spooky {}

然而,正如@LouisWasserman在评论中提到的那样:

  

我不相信有任何方法可以从局部变量中获取注释。

另见SO问题ElementType.LOCAL_VARIABLE annotation type和上述JLS:

  

<强> 9.6.4.1。 @target

     

[...]

     

本地变量声明的注释永远不会保留在二进制表示中。

所以,如果你让house一个字段(a.k.a。成员变量):

@Spooky
private House house = new House();

你可以使用:

Stream.of( this.getClass().getDeclaredFields() )
    .forEach( field -> Stream.of( field.getAnnotations() )
        .forEach( annotation -> System.out.printf( "@%s%n%s %s %s;%n",
            annotation.annotationType().getSimpleName(),
            Modifier.toString( field.getModifiers() ),
            field.getType().getSimpleName(),
            field.getName() ) ) );

或者如果您想明确获取house字段:

try {
    final Field field = this.getClass().getDeclaredField( "house" );
    final Spooky spooky = field.getAnnotation( Spooky.class );
    if ( spooky != null ) {
        System.out.printf( "@%s%n%s %s %s;%n",
            spooky.annotationType().getSimpleName(),
            Modifier.toString( field.getModifiers() ),
            field.getType().getSimpleName(),
            field.getName() );
    }
}
catch ( NoSuchFieldException | SecurityException e ) {
    e.printStackTrace();
}

两种情况下的输出:

@Spooky
private House house;

但是,正如您所看到的,即使使用流的简洁性,您的代码也不会变得更加清晰。我会考虑评论中提出的问题。