Java反射与APT相关知识小结(个人笔记)

883 阅读3分钟

结构体语言

对于Java源文件来说,它同样也是一种结构体语言:

package top.cyixlq.example; // PackageElement 包元素(element)/节点
public class Main { // TypeElement 类元素(element)/节点
    private int x;  // VariableElement 属性元素(element)/节点
    private void main() { // ExecuteableElement 方法元素(element)/节点
    }
}

自定义注解

  1. 元注解:最初的注解,作用在注解上的注解。例如:@Target、@Retention
  2. @Target:指定该自定义注解的作用目标,分为以下情况 --->>>
    • ElementType.TYPE:该自定义注解作用于接口、类、枚举和注解(类)之上
    • Element.FIELD:该自定义注解作用于属性和枚举的常量之上
    • Element.METHOD:该自定义注解作用于方法之上
    • Element.PARAMETER:该自定义注解作用于方法参数之上
    • Element.CONSTRUCTOR:该自定义注解作用于构造函数之上
    • Element.LOCAL_VARIABLE:该自定义注解作用于局部变量之上
    • Element.ANNOTATION_TYPE:该自定义注解作用于另一个注解之上
    • Element.PACKAGE:该自定义注解作用于包之上
  3. @Retention:指定改自定义注解声明周期(什么时候存在),分为以下情况 --->>>
    • RetentionPolicy.RUNTIME:运行时存在,需要在运行时动态获取注解信息使用
    • RetentionPolicy.CLASS:编译时存在,在要编译时进行一些预处理,但在运行时会被丢弃
    • RetentionPolicy.SOURCE:还是源码是存在,做一些检查性操作,注解仅在源码级别时存在,在编译的时候会被丢弃,例如@Override
  4. 每个注解中如果加入一个value()方法,那么使用该注解时往注解传入参数不需要指定参数名。仅在该自定义注解中只有一个value()方法时起作用。如果还有其他传值方法,value还是需要明确指定。(这一条内容仅方便作者记忆)

Class中一些常用API

  1. getEnclosedElements():返回该元素直接包含的子元素
  2. getEnclosingElements():返回包含该element的父element,与上一个方法相反
  3. getKind():返回element的类型,判断是那种element
  4. getModifiers():获取修饰关键字,如public static final等关键字
  5. getSimpleName():获取类名,不带包名那种
  6. getQualifiedName():获取全名,如果是类的话会带上完整包名那种
  7. getParameters():获取方法参数element,每个element是一个VariableElement
  8. getReturnType():获取方法element的返回值
  9. getConstantValue():如果属性变量被final修饰,可以使用该方法获取它的值

AbstractProcessor

经常需要重写的方法的作用:

  1. init(ProcessingEnvironment processingEnv),初始化方法,通过这个方法可以拿到一些常用的工具属性,例如:
    Filer filer = processingEnv.getFiler(); // 文件操作工具
    Elements elementUtils = processingEnv.getElementUtils(); // 元素工具
    Messager messager = processingEnv.getMessager(); // 信息打印工具
    
  2. getSupportedSourceVersion(),需要返回SourceVersion,指定jdk的编译版本,例如:
    return SourceVersion.latestSupported();
    
  3. getSupportedAnnotationTypes(),需要返回一个String的set集合,集合中放的是注解带完整包名的类名,指定哪些注解是需要处理的,例如:
    Set<String> types = new HashSet<>();
    types.add(Modules.class.getCanonicalName());
    types.add(Module.class.getCanonicalName());
    types.add(RouterPath.class.getCanonicalName());
    return types;
    
  4. getSupportedOptions(),接收参数方法,用例暂无,暂不理解此方法
  5. process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv):开始处理注解生成Java源文件的方法,最主要的操作在这个方法中。需要返回一个boolean值,如果为true代表已经自行处理好了注解,否则就是交给父级处理,类似于安卓触摸事件的传递处理。