目录
1 元注解
1.1 @Target
指定注解可应用的元素类型(类、方法、字段等)
1.2 @Retention
指定注解保留策略(SOURCE/CLASS/RUNTIME)
1.2.1 RetentionPolicy.SOURCE
源码保留,并被编译器忽略
1.2.1.1 APT
在编译期能够获取注解与注解声明的类包括类中所有成员信息,一般用于生成额外的辅助类。
实现步骤:
1、创建annotation模块(Java 或 Kotlin Library模块),存放注解
2、创建processor模块(Java 或 Kotlin Library模块),实现注解处理器:继承AbstractProcessor类,重写process方法(如下)
3、在app模块中使用注解处理器:annotationProcessor project(‘:processor’)
4、注册注解处理器
4.1、processor/src/main/resources/META-INF/services/目录下创建文件javax.annotation.processing.Processor,内容为处理器的全类名
4.2、使用AutoService简化
AbstractProcessor(注解处理器)
注解处理器执行多次(通常两次)是 Java 编译器多轮处理机制的正常表现
1、第一轮:处理原始代码中的注解
第一次调用process()时,处理器会扫描原始源代码(开发者编写的代码)中的注解,执行核心逻辑(如解析注解、生成代码)。
2、第二轮:处理生成代码中的注解(或收尾)
如果第一轮生成了新的 Java 代码,编译器会将这些代码视为 “新的源代码”,触发第二轮处理:
# 若生成的代码中包含新的注解(如@Generated或自定义注解),第二轮会处理这些新注解。
# 若生成的代码中没有注解,第二轮的RoundEnvironment会是空的,但处理器仍会被调用一次,此时RoundEnvironment.processingOver()返回true(表示处理即将结束),处理器可在此轮做收尾工作(如释放资源)。
如何处理多轮调用:
1、在process()中先判断是否有需要处理的注解
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
// 若本轮无注解且处理即将结束,直接返回
if (roundEnvironment.processingOver() || set.isEmpty()) {
return false;
}
// 处理注解的核心逻辑(仅在有注解时执行)
processAnnotation(roundEnvironment);
return true;
}
2、记录已处理的元素,避免重复处理
private Set<Element> processedElements = new HashSet<>();
private void processAnnotation(RoundEnvironment roundEnv) {
Set<? extends Element> elements = roundEnv.getElenentsAnnotatedWith(MyAnnotation.class);
for (Element elenent : elements) {
if (processedElements.contains(element)(
continue; //跳过已处理的元素
}
processedElements.add(element);
//生成代码...
}
}
1.2.1.2 @IntDef
AndroidX 注解库提供的一个元注解,主要作用是实现整数常量的类型安全,替代枚举(Enum)以优化性能,尤其在 Android 开发中被广泛使用。
背景:
枚举(Enum):类型安全,但每个枚举实例都是一个对象,占用更多内存和性能(尤其在 Android 这种资源受限的环境中)。
整数常量(public static final int):轻量,但缺乏类型检查,调用方法时可能传入无效的整数值,导致逻辑错误。
用法:
public class Status {
//1.定义整数常量
public static final int IDLE = 0;
public static final int RUNNING = 1;
public static final int PAUSED = 2;
public static final int STOPPED = 3;
//2.用@IntDef标记允许的常量,并用@Retention指定保留策略
@IntDef({IDLE,RUNNING,PAUSED,STOPPED}) // 限定只能使用这几个常量
@Retention(RetentionPolicy.SOURCE) // 仅在源码中保留(编译时检查)
public @interface Validstatus {} // 自定义注解,用于后续标记变量/参数
}
public class Permission {
//定义标志位常量(通常是2的幂,方便位运算)
public static final int READ = 1 << 0; // 1
public static final int WRITE = 1 << 1; // 2
public static final int DELETE = 1 << 2;// 4
//添加flag = true,表示允许常量组合(通过|运算)
@IntDef(flag = true, value = {READ, WRITE, DELETE})
@Retention(RetentionPolicy.SoURCE)
public @interface Permissions {}
}
//使用:允许组合多个常量
public void requestPermission(@Permission.Permissions int permission) {
// 例如:同时请求读和写权限
requestPermission(Permission.READ | Permission.WRITE);
}
1.2.2 RetentionPolicy.CLASS
字节码保留,但JVM会忽略
1.2.2.1 字节码增强技术
在 Java 字节码(.class 文件)生成后、加载前或运行时动态修改字节码的技术
场景:
AOP(面向切面编程):在不修改业务代码的情况下,为多个类的方法统一添加日志、事务、权限校验等逻辑
性能监控:自动为方法添加执行时间统计、调用次数记录等(如 Android 中的性能监控工具)–
热修复:动态替换有问题的方法字节码,修复线上 bug(如早期 Android 热修复方案)
代码生成优化:在编译期动态生成辅助代码,减少手动编写的模板代码(如 Dagger、ButterKnife 的部分逻辑)
兼容性适配:为不同版本的类添加适配逻辑,避免修改源代码
工具:
ASM:底层工具,直接操作字节码指令,性能极高,学习成本高,适用于性能敏感场景,如Android
Javassist:高层 API,支持用类似 Java 的语法修改字节码,无需了解字节码指令,性能中等,适合快速开发、逻辑简单的场景
1.2.3 RetentionPolicy.RUNTIME
由JVM保留,运行时会使用
与反射技术相结合,从而完成不同的逻辑判定
7594

被折叠的 条评论
为什么被折叠?



