注解Annotation
从 JDK 5.0 开始, Java 增加了对元数据(MetaData) 的支持, 也就是 Annotation(注解)。
Annotation 其实就是代码里的特殊标记, 这些标记可以在编译, 类加载, 运行时被读取, 并执行相应的处理。通过使用 Annotation, 程序员可以在不改变原有逻辑的情况下, 在源文件中嵌入一些补充信息。
Annotation 可以像修饰符一样被使用, 可用于修饰包, 类, 构造器, 方法, 成员变量, 参数,局部变量的声明 , 这些信息被保存在 Annotation 的 “name=value” 对中。我们可以通过反射机制编程实现对这些元数据的访问。
Annotation 能被用来为程序元素(类, 方法, 成员变量等) 设置元数据。
在Java SE中,注解的使用目的比较简单,例如标记过时的方法,忽略警告等。 在Java EE / Android中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替JavaEE旧版中所遗留的繁冗代码和XML配置。
未来的开发模式都是基于注解的,JPA是基于注解的,Spring2.5以上都是基于注解的,Hibernate3.x以后也都是基于注解的,Struts2也有一部分是基于注解的了。 注解是一种趋势, 一定程度上可以说:
 框架 = 注解 + 反射 + 设计模式。
Annotation 架构

(1). 1 个 Annotation 和 1 个 RetentionPolicy 关联。 可以理解为:每1个Annotation对象,都会有唯一的RetentionPolicy属性。
(2). 1 个 Annotation 和 1~n 个 ElementType 关联。 可以理解为:对于每 1 个 Annotation 对象,可以有若干个 ElementType 属性。
(3). Annotation 有许多实现类,包括:Deprecated, Documented, Inherited, Override 等等。 Annotation 的每一个实现类,都 “和 1 个 RetentionPolicy 关联” 并且 “ 和 1~n 个 ElementType 关联”。
Annotation 组成部分

JavaAnnotation 的组成中有 3 个非常重要的主干类。它们分别是:
Annotation.java:
| 1 | package java.lang.annotation; | 
Annotation 就是个接口。
每 1 个
Annotation“ 都与 “1 个RetentionPolicy“ 关联,并且与 “1~n 个ElementType“ 关联。可以通俗的理解为:每 1 个Annotation对象,都会有唯一的RetentionPolicy属性;至于ElementType属性,则有 1~n 个。
ElementType.java:
| 1 | package java.lang.annotation; | 
ElementType 是 Enum 枚举类型,它用来指定 Annotation 的类型。
每 1 个 Annotation“ 都与 “1~n 个 ElementType“ 关联。当 Annotation 与某个 ElementType 关联时,就意味着:Annotation有了某种用途。例如,若一个 Annotation 对象是 METHOD 类型,则该 Annotation 只能用来修饰方法。
RetentionPolicy.java:
| 1 | package java.lang.annotation; | 
RetentionPolicy 是 Enum 枚举类型,它用来指定 Annotation 的策略。通俗点说,就是不同 RetentionPolicy 类型的 Annotation 的作用域不同。
每 1 个 Annotation 都与 1 个 RetentionPolicy关联 :
a) 若
Annotation的类型为SOURCE,则意味着:Annotation仅存在于编译器处理期间,编译器处理完之后,该Annotation就没用了。 例如,” @Override” 标志就是一个 Annotation。当它修饰一个方法的时候,就意味着该方法覆盖父类的方法;并且在编译期间会进行语法检查!编译器处理完后,”@Override” 就没有任何作用了。b) 若
Annotation的类型为CLASS,则意味着:编译器将Annotation存储于类对应的.class文件中,它是Annotation的默认行为。c) 若
Annotation的类型为RUNTIME,则意味着:编译器将Annotation存储于class文件中,并且可由JVM读入。 也就是说可以通过反射机制来读取。
JDk中的内置注解
Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。
使用 Annotation 时要在其前面增加 @ 符号, 并把该 Annotation 当成一个修饰符使用。用于修饰它支持的程序元素。
@Override
定义在java.lang.Override中,此注解只适用修饰方法,表示一个方法声明重写父类中的另一个方法声明。 如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
@Deprecated
定义在java.lang.Deprecated中, 用于表示某个程序元素(类, 方法等)已过时。此注解可用于修辞方法、属性、类 ,表示不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。
| 1 | 
 | 
@ SuppressWarnings
定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息。
| 1 | 
 | 
(1) @interface – 它的用来修饰 SuppressWarnings,意味着 SuppressWarnings 实现了java.lang.annotation.Annotation 接口;即 SuppressWarnings 就是一个注解 。
(2) @Retention(RetentionPolicy.SOURCE) – 它的作用是指定 SuppressWarnings 的策略是 RetentionPolicy.SOURCE。这就意味着,SuppressWarnings 信息仅存在于编译器处理期间,编译器处理完之后 SuppressWarnings 就没有作用了。
(3) @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) – 它的作用是指定 SuppressWarnings 的类型同时包括TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE。
(04) String[] value(); 意味着,SuppressWarnings 能指定参数 。
与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数值都是已经定义好了的,我们选择性的使用就好了,参数如下:
| 1 | deprecation -- 使用了不赞成使用的类或方法时的警告 | 
(5) SuppressWarnings 的作用是,让编译器对”它所标注的内容”的某些警告保持静默。例如,”@SuppressWarnings(value={"deprecation", "unchecked"})“ 表示对”它所标注的内容”中的 “SuppressWarnings 不再建议使用警告”和”未检查的转换时的警告”保持沉默。
自定义注解
Annotation 通用定义
| 1 | 
 | 
定义新的 Annotation 类型使用 @interface 关键字。
自定义注解自动继承了java.lang.annotation.Annotation 接口。
Annotation的成员变量在 Annotation 定义中以无参数方法的形式来声明。其方法名和返回值定义了该成员的名字和类型。称之为配置参数。例如: String[] values();
如果只有一个参数成员,一般参数名为value
可以在定义 Annotation 的成员变量时为其指定初始值, 指定成员变量的初始值可使用default关键字。
| 1 | public MyAnnotation{ | 
没有成员定义的 Annotation 称为标记, 比如 @Override; 包含成员变量的 Annotation 称为元数据 Annotation, 再使用该注解的时候要使用成员变量,指定值。
注: 自定义注解必须定义注解信息处理流程才有意义。 (注解信息处理流程,是注解和注释的重大区别 。如果没有注解信息处理流程,则注解毫无意义)。使用反射实现。
元注解
元注解的作用就是负责注解其他注解, 对现有的注解进行解释说明的注解。(注解注解的注解。…晕)
JDK5.0提供了专门在注解上的注解类型,分别是:
@Retention
@Target
@Documented
@Inherited
元数据: String name = "zhu"; 其中 String name 就是一个元数据, 用来修饰主要数据(”zhu”)的数据。
@Retention
只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留多长时间(生命周期)。
@Rentention 包含一个 RetentionPolicy 类型的成员变量, 使用 @Rentention 时必须为该 value 成员变量指定值。
RetentionPolicy.SOURCE : 编译器直接丢弃这种策略的注释, 编译成class文件中不会保留该注解信息。
RetentionPolicy.CLASS: 编译器将把注释记录在 class 文件中。当运行 Java 程序时,
JVM不会保留注解。 这是默认值。RetentionPolicy.RUNTIME: 编译器将把注释记录在class文件中。当运行Java程序时, JVM会保留注解。程序可以通过反射获取该注解。
可以参考上文[@Retention](#Annotation 组成部分).
@Target
前面我们说过,ElementType 是 Annotation 的类型属性。而 @Target 的作用,就是来指定 Annotation 的类型属性。查看[ElementType ](# ElementType.java:)。
用于修饰 Annotation 定义, 用于指定被修饰的 Annotation 能用于修饰哪些程序元素。@Target 也包含一个名为 value 的成员变量。
定义 Annotation 时,@Target 可有可无。若有 @Target,则该 Annotation 只能用于它所指定的地方;若没有 @Target,则该 Annotation 可以用于任何地方。
如:
| 1 | 
 | 
@Inherited
被它修饰的 Annotation 将具有继承性.如果某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自动具有该注解。 实际开发中应用的较少。
@Documented
用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档。
定义为
Documented的注解必须设置Retention值为RUNTIME。
JDK8中注解的新特性
可重复注解
在JDK8之前,如果需要使用重复注解:
| 1 | package annotation; | 
需要定义一个注解,里面加入要重复注解类型的数组:
| 1 | package annotation; | 
使用:
| 1 | 
 | 
在JDk8之后:使用@Repeatable 可以实现可重复注解。
①. 在MyAnnotation上声明@Repeatable, 成员值为@Repeatable.class`。
②. MyAnnotation 的 Target 与 Retention 等元注解和 MyAnnotations的要相同。
③. 使用可重复注解:
| 1 | 
 | 
| 1 | 
 | 
类型注解
来看看jdk8中的ElementType的定义。
| 1 | public enum ElementType { | 
在Java8之前, 注解只能是在声明的地方所使用的, Jva8之后, 注解可以应用到任何地方。
TYPE_PARAMETER : 表示该注解能写在类型变量的声明语句中(如: 泛型声明)。
TYPE_USE : 表示该注解能卸载使用类型的任何语句中。
定义一个注解:
| 1 | 
 | 
| 1 | class Generic<@MyAnnotation T>{ | 
注解的作用
- 编译检查: @SuppressWarnings,@Deprecated和@Override都具有编译检查作用。 若某个方法被@Override的标注,则意味着该方法会覆盖父类中的同名方法。如果有方法被@Override标示,但父类中却没有”被@Override标注”的同名方法,则编译器会报错。
- 可以在反射中使用Annotation: 在反射的 Class,Method,Field等函数中,有许多于 Annotation 相关的接口。这也意味着,我们可以在反射中解析并使用Annotation。
- 根据 Annotation 生成帮助文档: 通过给 Annotation注解加上@Documented标签,能使该Annotation标签出现在javadoc中。
- 能够帮忙查看代码: 通过 @Override,@Deprecated等,我们能很方便的了解程序的大致结构。另外,我们也可以通过自定义Annotation来实现一些功能。
实例: 通过反射模拟注解信息处理流程
模拟ORM: Object Relation Mapping
数据库中表对应着Java中的一个类, 字段对应属性,本例通过读取类上的注解来生成一个sql语句来创建一个数据库中表。
定义类上的注解
| 1 | package annotation; | 
定义字段Field的注解
| 1 | package annotation; | 
Person类上使用注解
| 1 | package annotation; | 
第三方程序通过反射机制读取注解
| 1 | package annotation; | 
总结
@interface 用来声明 Annotation。
@Documented 用来表示该 Annotation 是否会出现在 javadoc 。
@Target 用来指定 Annotation 的类型。
@Retention 用来指定 Annotation 的策略。


