元注解在JDK中已被定义,元注解主要用于对自定义的注解进行描述,也可以理解为注解的注解。
JDK定义了四种元注解,用来对注解的位置、作用范围、文档抽取、继承进行描述。这四种元注解分别是:@Target、@Retention、@Documented、@Inherited,下面分别对这四种元注解进行说明。
@Target
用于描述注解出现的位置,注解可以用于包、类、接口、类成员方法、类成员变量、方法参数、局部变量、枚举类型,JDK定义了ElementType枚举类型用于描述注解可以出现的位置,ElementType有如下枚举值:
ElementType.FIELD:注解仅用于添加到成员变量
ElementType.METHOD:注解仅用于添加到成员方法
ElementType.PARAMETER:注解仅用于添加到方法参数
ElementType.CONSTRUCTOR:注解仅用于添加到构造方法
ElementType.LOCAL_VARIABLE:注解仅用于添加到局部变量
ElementType.ANNOTATION_TYPE:注解仅用于添加到注解(元注解)
ElementType.PACKAGE:注解仅用于添加到包
描述注解可以使用多个枚举值。例如:如果希望注解添加到成员方法和成员变量上,可以使用ElementType.FIELD和ElementType.METHOD枚举值来描述注解。
示例:
@Target(ElementType.METHOD, ElementType.FIELD )
public @interface Demo {
......
}@Retention
用于描述注解的作用范围,即注解的有效范围。JDK定义了三种有效范围,分别是:注解作用于源代码(编译器可读取注解)、注解作用于类文件(在类文件中可读取注解)、注解作用于运行过程(用反射技术读取注解)。JDK定义了RetentionPolicy枚举类型用于描述注解作用范围,RetentionPolicy有如下枚举值:
RetentionPolicy.SOURCE:注解作用于源代码
RetentionPolicy.CLASS:注解作用于类文件
RetentionPolicy.RUNTIME:注解作用于运行时
示例:
@ Retention (RetentionPolicy.RUNTIME )
public @interface Demo {
......
}当注解作用范围选择RetentionPolicy.RUNTIME时,作用范围自然就满足类文件和源代码。
@Documented
使用@Documented描述的注解可以被javadoc工具抽取作为程序文档。它是一个标记注解,没有属性。
示例:
@ Documented
public @interface Demo {
......
}@Inherited
使用@Inherited描述的注解具有继承性,使用@Inherited注解的类,其子类将自动拥有该注解。它是一个标记注解,没有属性。
学习了元注解后,就可以解决前面一课案例读取Rate注解失败的问题,需要在Rate注解前面添加@ Retention (RetentionPolicy.RUNTIME )元注解。
为了不影响前面一课案例的源代码,本课重新编写案例代码。
案例1:建立NewRate注解,NewRate注解为其它类提供银行定期存款利率元数据。建立NewCalculation类,该类用于银行定期存款利息计算。定义一个成员变量rate,在rate变量前面添加注解NewRate,rate的值来自于NewRate注解提供的元数据rate。定义一个方法interest(),用于计算本金利息。建立NewCalculationTest测试类,验证NewRate注解的读取。
在annotation包下新建NewRate注解类。代码如下:
package annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @ClassName: NewRate
* @Description: 注解与反射(元注解)案例1
* @author 编程训练营
* @date
*
*/
//注解存在于运行时
@Retention(RetentionPolicy.RUNTIME)
public @interface NewRate {
// 利率默认值0.03
double rate() default 0.03;
}在NewRate注解前面添加元注解@Retention,元注解的值选择RetentionPolicy.RUNTIME,即注解作用范围为运行时。@Retention元注解和RetentionPolicy枚举类型都在java.lang.annotation包内,需要使用import语句导入。
在annotation包下新建NewCalculation类。代码如下:
package annotation;
/**
* @ClassName: NewCalculation
* @Description: 注解与反射(元注解)案例1
* @author 编程训练营
* @date
*
*/
public class NewCalculation {
// 添加Rate注解
@NewRate(rate = 0.035)
double dRate;
public NewCalculation()
{
dRate = 0.0;
}
/**
* @Title: interest
* @Description: 计算定期存款利息
* @param @param capital @param @param
* year @param @return 参数
*
* @return double 返回类型 @throws
*/
public double interest(double capital, int year) {
return capital * dRate * year;
}
/**
* @return the dRate
*/
public double getdRate() {
return dRate;
}
/**
* @param dRate the dRate to set
*/
public void setdRate(double dRate) {
this.dRate = dRate;
}
}如果注解类和使用注解的类不在同一个包内,需要使用import语句将注解类导入。NewRate注解添加到NewCalculation类dRate成员变量上,也可以同时添加到其它变量上。
在annotation包下新建NewCalculationTest测试类。代码如下:
package annotation;
import java.lang.reflect.Field;
/**
* @ClassName: NewCalculationTest
* @Description: 注解与反射(元注解)案例1
* @author 编程训练营
* @date
*
*/
public class NewCalculationTest {
/**
* @Title: main
* @Description:Java程序入口main方法
* @param @param args 参数
*
* @return void 返回类型 @throws
*/
public static void main(String[] args) {
// 实例化Calculation类
NewCalculation calcula = new NewCalculation();
// 获取Calculation类的Class对象
Class calculaClass = calcula.getClass();
try {
// 通过class.getDeclaredField(name)获取指定名称的成员变量
Field field = calculaClass.getDeclaredField("dRate");
// 获取该成员变量上的Rate注解
NewRate rate = field.getAnnotation(NewRate.class);
// 判断注解是否获取成功
if (null != rate) {
// 注解对象直接访问rate属性
calcula.setdRate(rate.rate());
System.out.printf("定期存款年利息为:%.2f/%%\n", rate.rate() * 100);
System.out.println("15000元存款2年定期存款利息为:" + calcula.interest(15000, 2));
} else {
System.out.println("获取Rate注解失败");
}
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}NewCalculationTest程序首先通过NewCalculation实例获取Class对象,通过Class对象的getDeclaredField()方法获取NewCalculation类成员变量dRate的Field对象,在通过Field类的getAnnotation()方法获取NewRate注解,返回的注解对象引用赋值给NewRate类型的局部变量rate。
程序执行结果如下图所示:

从程序执行结果可以看出,NewCalculation类的NewRate注解的属性被成功读取,并设置到calcula对象的dRate成员变量。