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
。