一、注解简介
注解是那些插入到源代码中使用其他工具可以对其进行处理的标签。这些工具可以在源码层次上进行操作,或者可以处理编译器在其中放置了注解的类文件。
注解不会改变程序的编译方式。Java编译器对于包含注解和不包含注解的代码会生成相同的虚拟机指令。
为了能够受益于注解,你需要选择一个处理工具,然后向你的处理工具可以理解的代码中插入注解,之后运用该处理工具处理代码。
Java中,注解是当作一个修饰符来使用的,它被置于被注解项之前,中间没有分号。每一个注解的名称前面都加上了@符号。
二、注解语法
1、注解的定义
注解是由注解接口来定义的:
modifiers @interface AnnotationName {
elementDeclaration1
elementDeclaration2
...
}
每个元素的声明都具有下面这种形式:
type elementName();
或者
type elementName() default value;
比如我们常用,Spring中用来标记为Bean的注解定义:其中包含一个元素:value
public @interface Component {
String value() default "";
}
所有的注解接口都隐式的扩展自java.lang.annotation.Annotation接口,这个接口是一个常规接口,不是一个注解接口。你无法扩展注解接口,换句话说,所有的注解接口都直接扩展自java.lang.annotation.Annotation。
注解元素的类型为下列之一:
- 基本类型(int、short、long、byte、char、double、boolean)
- String
- Class(具有一个可选的类型参数,例如Class<? extends MyClass>)
- enum类型
- 注解类型
- 上述所述类型组成的数组
下面是个合法的元素声明的例子:
public @interface BugReport {
enum Status { UNCONFIRMED, CONFIRMED, FIXED, NOTABUG };
boolean showStopper() default false;
String assignedTo() default "[none]";
Class<?> testCase() default Void.class;
Status status() default Status.UNCONFIRMED;
Reference ref() default @Reference(); // an annotation type
String[] reportedBy();
}
2、注解的使用
@BugReport(severity=10, assignedTo="Harry")
其中元素的顺序无关紧要,如果某个元素的值未指定,那么就会使用声明的默认值。
可以简化写法:如果没有指定元素,要么是因为注解中没有元素,或者使用默认值,这个时候就不用使用圆括号了()。例如:@BugReport。这样的注解又称为标记注解。
另外一个快捷方式是单值注解。如果元素具有特殊名字value,并且没有指定其他元素,那么就可以忽略掉这个元素名以及等号。例如:@Component("beanName")。
值得注意的是:
- 因为注解是由编译器计算而来的,因此,所有元素的值必须是编译器常量。
- 一个注解元素永远不能设置为null,甚至不允许默认值为null,这样在实际应用中会相当不方便,必须使用其他默认值。
如果元素值是一个数组,需要将它的值用括号括起来:
@BugReport(. . . reportedBy={"Harry","Carl"})
如果数组元素是个单值,则可以忽略括号:
@BugReport(. . . reportedBy="Harry")
3、注解的各类声明
注解可以出现在许多地方,这些地方可以分为两类:声明和类型用法声明注解可以出现在下列声明处:
- 包
- 类(包括enum)
- 接口(包括注解接口)
- 方法
- 构造器
- 实例域(包含enum常量)
- 局部变量
- 参数变量
- 类型参数
对于类和接口,需将注解放在class和interface关键词前面。
对于变量,需将注解放置在类型的前面
泛化类或方法中的参数可以像下面这样被注解
public class Cache<@Immutable V> {.....}
包是在文件package-info.java中注解的,该文件只包含以注解先导的包语句。
/**
Package-level Javadoc
*/
@GPL(version="3")
package com.horstmann.corejava;
import org.gnu.GPL;
三、标准注解
Java SE在java. lang、java.lang.annotation和javax.annotation包中定义了大量的注解接口。其中四个是元注解,用于描述注解接口的行为属性,其他的三个是规则接口,可以用它们来注解你的源代码中的项。下表列出了这些注解。
1、用于编译的注解
@Deprecated注解可以被添加到任何不在被鼓励使用的项上,所以当使用一个过期的项时,编译器将会发出警告,这个注解与javadoc标签@deprecated具有同等功效。
@SuppressWarnings注解会告知编译器阻止特定类型的警告信息。
@Override这种注解只能用到方法上,编译器会检查这种注解的方法是否真正的覆盖了一个来自于超类的方法。
@Generated注解的目的是供代码生成工具来使用。
2、用于管理资源的注解
@PostConstruct和@PreDestroy注解用于控制对象生命周期的环境中,标记了这些注解的方法应该在对象被构建之后,或者在对象被移除之前,紧接着调用。
@Resource注解用于资源注入。
3、元注解
3.1、@Target元注解
@Target元注解可以应用于一个注解,以限制该注解可以应用到哪些项上。下表显示了所有可能的取值情况,它们属于枚举类型ElementType,可以指定任意数量的元素类型,用括号括起来。
一条没有@Target限制的注解可以应用于任何项上。
3.2、@Retention元注解
@Retention元注解用于指定一条注解应该保留多长时间,默认值是RetentionPolicy.CLASS。其他类型如下表所示:
3.3、@Documented元注解
@Documented元注解为像Javadoc这样的归档工具提供了一些提示,以实现其归档。
注意:将一个注解应用到它自身身上是合法的,例如@Documented注解被自身注解为@Documented。
3.4、@Inherited元注解
@Inherited元注解只能应用于对类的注解。如果一个类具有继承注解,那么它的所有子类都自动具有同样的注解。