是否可以将注释附加到新对象?
假设我们有一个简单的房子对象House house = new House ()
和注释@Large
和@Spooky
。
我的想法是设置一个切换声明,因此标记为@Spooky
的房屋与标有@Large
的房屋不同。
@Spooky
House house = new House();
System.out.println(house.getClass().getAnnotations().length);
显然,我的新房屋对象上没有注释length == 0
。
为什么?
答案 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 强>
注释类型可能适用于声明上下文,,其中注释适用于声明,或类型上下文,注释适用于声明和表达式中使用的类型。
[由我强调。]
正如@ M.Prokhorov在他对你的问题的评论中提到的那样,你没有注释你的House
类,而是house
的局部变量声明,即类型House
。< / p>
注释放置
您可以将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;
但是,正如您所看到的,即使使用流的简洁性,您的代码也不会变得更加清晰。我会考虑评论中提出的问题。