Logo

郎哥编程

元注解

2020-01-05 241

元注解在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。

程序执行结果如下图所示:

image.png

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

代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论