Java 注解 Annotation:代码中的特殊标记,这些标记可以在编译、类加载、运行时读取,并执行相应的解析处理。注解本身并不影响代码以及运行结果,只有在解析这些注解后才会生效。  
Annotation 很像一个接口(反编译后发现注解就是一个接口),通过 @interface 修饰来,同一个文件中只能有一个 Annotation 的定义。  
元注解
元注解 Meta Annotation,用来修饰其他 Annotation ,即表示“其他注解”的注解。  
@Retention
用于指定被修饰 Annotation 能保留多长时间。包含三个 RetentionPolicy 类型的 value 成员变量:  
RetentionPolicy.SOURCE
注解只保留在源代码中,编译时直接丢弃这些注解。RetentionPolicy.CLASS
编译器将注解记录在class文件中,在运行时JVM不再保留注解。它也是@Retention的默认值。RetentionPolicy.RUNTIME
编译器不仅将注解记录在class文件中,运行时JVM也会保留注解。也就是说程序想通过反射来获取注解信息,则必须使用RUNTIME类型。
使用 @Retention 的示例:  
1  | 
  | 
@Target
只能用来修饰一个 Annotation 的定义,用于指定被修饰的 Annotation 能够修饰哪些程序元素。包含如下 ElementType 类型的 value 成员变量:  
ElementType.TYPE:指定该注释可以修饰类、接口或枚举ElementType.FIELD:指定该注解只能修饰成员变量ElementType.METHOD:指定该注解只能修饰方法ElementType.PARAMETER:指定该注解只能修饰参数ElementType.CONSTRUCTOR:指定该注解只能修饰构造器ElementType.LOCAL_VARIABLE:指定该注解只能修饰局部变量(不能通过反射解析,class文件并不保留局部变量注解。只能通过源码在编译前解析)ElementType.ANNOTATION_TYPE:指定该注解只能修饰注解ElementType.PACKAGE:指定该注解只能修饰包定义ElementType.TYPE_PARAMETER:指定该注解只能参数化类型ElementType.TYPE_USE:指定该注解可以修饰上面几种任意类型
如果需要指定多个 ElementType 类型的成员变量,使用数组赋值。  
1  | // 修饰单个元素  | 
@Documented
修饰其他 Annotation 时,通过 javadoc 工具提取文档会保留这个 Annotation 信息。  
1  | 
  | 
javadoc 生成文档时,myJavaDocInfo 方法文档会保留 @Testable 信息。如果 Testable 的元注解中去掉 @Documented,则生成的文档不会保留 @Testable 信息。  
@Inherited
修饰其他 Annotation 时,表示该注解具有继承性。比如 @A 被 @Inherited 注解,@A 注解父类,则其所有子类自动被 @A 注解。  
1  | // 1. Annotation  | 
运行结果显示,虽然 Son 并没有被 Inheritable 注解,但是自动从 Father 那继承了该注解。  
@Repeatable
Java 8 加入的新特性,表示注解中相同元素的值可以取多个。比如某个类需要扮演多个角色:医生、护士、警察。在 Java 8 之前是不允许有相同注解重复的。  
1  | // 1. 定义角色注解  | 
元注解的源码
1  | // 1. Retention  | 
自定义注解
自定义注解使用 @interface 作为关键字。  
定义
格式,注意成员变量后有个双括号 (),以 ; 结尾:  
1  | 访问控制符 @interface 注解名称{  | 
- 标记 
Annotation
如果没有定义成员变量,则该注解被称为标记。这种注解仅仅利用自身存在来给我们提供信息,比如@Override等等。1
2
public TestPara{} - 元数据 
Annotation
包含成员变量,他们可以接受更多的元数据,每个成员变量可以有默认值,使用default关键字。1
2
3
4
5
6
7
public MetaAnnotation {
String author();
String date();
int currentVersion() default 1;
String[] reviewer();
} 
使用方法
格式:
1  | @自定义注解(成员变量1=指定值1,  | 
成员变量是以名字和值 name=value 形式成对出现的,如果只有一个,可以省略成员变量名称。被注解元素,是依据 @Target 指定的类型。  
1  | 
  | 
Java 预置的基本注解
@Override
@Override 只能注解方法,用来表示方法重写。编译器会检查该方法,保证父类要包含一个被重写的方法,否则会编译报错。  
1  | 
  | 
@Deprecated
@Deprecated 用于注解方法,类,字段等,表示该程序元素已过时。当其他程序调用时,编译器会给出警告。  
1  | 
  | 
@SuppressWarnings
@SuppressWarnings 注解表示取消显示指定的编译器警告。比如:unused, unchecked, all 等警告。  
1  | 
  | 
@SafeVarargs
Java 7 新增的注解,参数安全类型注解,它的目的是提醒开发者不要用参数做一些不安全的操作。比如堆污染:把一个不带泛型的对象赋给一个带泛型的变量是,就会发生堆污染。  
1  | 
  | 
@FunctionalInterface
Java 8 新增的注解,表示函数式接口注解。
函数式接口 Functional Interface:就是只有一个方法的普通接口,使用 @FunctionalInterface 注解后,编译器会检查确保符合规范。  
1  | 
  | 
其他
注解是一种类型
注解是具体的类型,可以使用 instanceof 来判断,示例:if (annotation instanceof GET) {...} 。  
注解的解析
- 通过反射处理注解
这种处理方式要求注解必须是@Retention(RetentionPolicy.RUNTIME)类型的。在运行时,通过反射来获取并解析注解。但是反射比较慢,所以需要考虑效率问题。 - 编译时处理注释
因为反射效率和性能问题,Java还提供了编译时解析注解并自动生成代码。Java 7之前可以使用APT: Annotation Processing Tool工具提取注解并解析后,生成对应的代码。但是Java 7开始降级移除了APT并采用JSR 269: Pluggable Annotation Processing API,原因及说明见官网解释,原因。 
参考文档
- 疯狂 
Java讲义 – 第 14 章Annotation注释 - 官方教程 Annotation
 - 秒懂 Java 注解
 - Java Annotation 及几个常用开源项目注解原理简析
 - 元注解之 Repeatable
 - Java 8 新特性:扩展注解