Java注解(2)注解的使用:编译时和运行时处理

目录:
1.注解的编译时处理
2.注解的运行时处理

上一篇学到注解的基本概念以及如何定义注解。
接下来学习如何提取注解(拿到注解的内容)并使用注解.

1.编译时处理:

原理:APT技术
处理对象:@Retention=Source的注解
编译时处理需要使用到APT技术,该技术提供了一套编译期的注解处理流程。

在编译期扫描.java文件的注解,并传递到注解处理器,注解处理器可根据注解生成新的.java文件,这些新的.java问和原来的.java一起被javac编译。

这里需要引入注解处理器这个概念,注解处理器是一个在javac编译期处理注解的工具,你可以创建注解处理器并注册,在编译期你创建的处理器以Java代码作为输入,生成文件.java文件作为输出。
注意:注解处理器不能修改已经存在的Java类(即不能向已有的类中添加方法)。只能生成新的Java类。

2.运行时处理

原理: 通过反射机制获取注解。
处理对象:@Retention=RUNTIME的注解

2.1判断某个注解是否存在于Class、Field、Method或Constructor:

Class.isAnnotationPresent(Class)
Field.isAnnotationPresent(Class)
Method.isAnnotationPresent(Class)
Constructor.isAnnotationPresent(Class)

例如:判断某个注解是否存在于Class

Class cls = Person.class;
if (cls.isAnnotationPresent(Report.class)) {
    Report report = cls.getAnnotation(Report.class);
    ...
}

判断某个注解是否存在于Field、Method或Constructor中与Class类似。
2.2直接从Class、Field、Method或Constructor读取到Annotation:

Class.getAnnotation(Class)
Field.getAnnotation(Class)
Method.getAnnotation(Class)
Constructor.getAnnotation(Class)

例如直接从Class中读取Annotation:

Class cls = Person.class;
Report report = cls.getAnnotation(Report.class);
if (report != null) {
   ...
}

直接从Field、Method或Constructor中与从Class中读取类似。

2.3读取方法参数的Annotation
比从Class、Field、Method或Constructor读取麻烦一点。
因为方法参数本身可以看成一个数组,而每个参数又可以定义多个注解,所以,一次获取方法参数的所有注解就必须用一个二维数组来表示。例如,对于以下方法定义的注解:

public void hello(@NotNull @Range(max=5) String name, @NotNull String prefix) {
}

要读取方法参数的注解,我们先用反射获取Method实例,然后读取方法参数的所有注解:

// 获取Method实例:
Method m = ...
// 获取所有参数的Annotation:
Annotation[][] annos = m.getParameterAnnotations();
// 第一个参数(索引为0)的所有Annotation:
Annotation[] annosOfName = annos[0];
for (Annotation anno : annosOfName) {
    if (anno instanceof Range) { // @Range注解
        Range r = (Range) anno;
    }
    if (anno instanceof NotNull) { // @NotNull注解
        NotNull n = (NotNull) anno;
    }
}

读取到注解后,就可以进行实际的业务代码处理了。

运行时处理注解的缺点:
1:通过反射会影响运行效率
2:如果注解无法保存到运行时的话,是无法使用运行时处理的

参考:
编译时处理参考
APT技术
运行时注解处理参考

原文地址:https://www.cnblogs.com/JohnTeslaaa/p/12720500.html