14.2 JDK的元注解
14.2 JDK的元注解
JDK除在java.lang下提供了5个基本的注解之外,还在java.lang.annotation包下提供了6个Meta注解(元注解,其中有5个元注解都用于修饰其他的注解定义。其中@Repeatable专门用于定义Java8新增的重复注解,本章后面会重点介绍相关内容。此处先介绍常用的4个元注解。
java.lang.annotation包中用于修饰其他注解定义的注解
- @Retention
- @Target
- @Documented
- @Inherited
14.2.1 使用@Retention
@Retention只能用于修饰注解定义,用于指定被修饰的注解可以保留多长时间,@Retention包含一个RetentionPolicy类型的value成员变量,所以使用@Retention时必须为该value成员变量指定值。
value成员变量的值只能是如下三个
| 属性 | 描述 |
|---|---|
RetentionPolicy.CLASS |
编译器将把注解记录在class文件中。当运行Java程序时,JVM不可获取注解信息。这是默认值。 |
RetentionPolicy.RUNTIME |
编译器将把注解记录在class文件中。当运行Java程序时,JVM也可获取注解信息,程序可以通过反射获取该注解信息。 |
RetentionPolicy.SOURCE |
注解只保留在源代码中,编译器直接丢弃这种注解。 |
如果需要通过反射获取注解信息,就需要使用value属性值为RetentionPolicy.RUNTIME的@Retention。使用@Retention元注解可采用如下代码为value指定值
1 | 定义下面的 注解保留到运行时 |
也可采用如下代码来为value指定值。
1 | //定义下面的 @Testable注解将被编译器直接丢弃 |
当注解的成员变量名为value时可以省略value
上面代码中使用@Retention元注解时,并未通过value=RetentionPolicy.SOURCE的方式来为该成员变量指定值,这是因为当注解的成员变量名为value时,程序中可以直接在注解后的括号里指定该成员变量的值,无须使用name=Value的形式。
如果使用注解时只需要为value成员变量指定值,则使用该注解时可以直接在该注解后的括号里指定value成员变量的值,无须使用“value=变量值”的形式
14.2.2 使用@Target
Target也只能修饰注解定义,它用于指定被修饰的注解能用于修饰哪些程序单元。@Target元注解也包含一个名为value的成员变量,该成员变量的值只能是如下几个。
| 属性 | 描述 |
|---|---|
ElementType.ANNOTATION_TYPE |
指定该策略的注解只能修饰注解。 |
ElementType.CONSTRUCTOR |
指定该策略的注解只能修饰构造器 |
ElementType.FIELD |
指定该策略的注解只能修饰成员变量。 |
ElementType.LOCAL_VARIABLE |
指定该策略的注解只能修饰局部变量 |
ElementType.METHOD |
指定该策略的注解只能修饰方法定义 |
ElementType.PACKAGE |
指定该策略的注解只能修饰包定义。 |
ElementType.PARAMETER |
指定该策略的注解可以修饰参数。 |
ElementType.TYPE |
指定该策略的注解可以修饰类、接口(包括注解类型)或枚举定义。 |
与使用@Retention类似的是,使用@Target也可以直接在括号里指定value值,而无须使用name=Value的形式。
代码 指定一个注解只能修饰成员变量
如下代码指定@ActionListenerFor注解只能修饰成员变量。
1 |
|
代码 指定一个注解只能修饰方法
如下代码片段指定@Testable注解只能修饰方法。
1 | ; |
14.2.3 使用@Documented
@Documented用于指定被@Documented注解修饰的注解类将被javadoc工具提取成文档,如果定义注解类时使用了@Documented修饰,则所有使用该注解修饰的程序元素的API文档中将会包含该注解说明。
程序
下面代码定义了一个Testable注解,程序使用 @Documented来修饰tEstable注解定义,所以该注解将被javadoc工具所提取。
1 | import java.lang.annotation.*; |
上面代码中的粗体字代码指定了javadoc工具生成的API文档将提取@Testable的使用信息下面代码定义了一个MyTest类,该类中的inf()方法使用了@Testable修饰。
1 | public class MyTest { |
使用javadoc工具为Testable.java、MyTest.java文件生成API文档
1 | javadoc Testable.java MyTest.java -d api |
效果如图14.1所示。
如果把上面Testable.java程序中的注解@Documented删除或注释掉,再次使用javadoc工具生成的API文档如图14.2所示
对比图14.1和142所示两份API文档中灰色区域覆盖的info()方法说明,图1411中的info()方法说明里包含了@Testable的信息,这就是使用@Documented元Annotation的作用

14.2.4 使用@Inherited
@Inherited元注解指定被它修饰的注解将具有继承性:如果某个类使用了@Xxx注解(定义该注解时使用了@Inherited修饰)修饰,则其子类将自动被@Xxx修饰。
程序
下面使用 @Inherited元注解修饰@Inheritable定义,则该注解将具有继承性。
1 | import java.lang.annotation.*; |
上面程序表明@Inheritable具有继承性,如果某个类使用了@Inheritable修饰,则该类的子类将自动使用 @Inheritable修饰。
下面程序中定义了一个Base基类,该基类使用了 @Inheritable修饰,则Base类的子类将会默认使用 @Inheritable修饰。
1 | // 使用@Inheritable修饰的Base类 |
上面程序中的Base类使用了@Inheritable修饰,而该注解具有继承性,所以其子类也将自动使用@Inheritable修饰。运行上面程序,会看到输出:true
如果将InheritableTest.java程序中的粗体字代码注释掉或者删除,将会导致@Inheritable不具有继承性。运行上面程序,将看到输出:false。