又称Java标注,是一种注释机制。注解是元数据的一种形式,为代码添加一些额外信息。使用关键字@interface
定义。
1. 元注解
- 定义:对注解类型进行注解的注解类。一般在定义注解类型时,需要指定的元注解有两个:`@Target`和`@Retention`。另外还有`@Documented`和`@Inherited`。
- `@Target`:定义Annotation所修饰的对象类型
- ElementType.ANNOTATION_TYPE 可以应用于注解类型。
- ElementType.CONSTRUCTOR 可以应用于构造函数。
- ElementType.FIELD 可以应用于字段或属性。
- ElementType.LOCAL_VARIABLE 可以应用于局部变量。
- ElementType.METHOD 可以应用于方法级注解。
- ElementType.PACKAGE 可以应用于包声明。
- ElementType.PARAMETER 可以应用于方法的参数。
- ElementType.TYPE 可以应用于类的任何元素。
- `@Retention` 指定注解的生命周期
- RetentionPolicy.SOURCE - 仅保留在源级别中,当Java文件编译成class文件时,注解被遗弃。可用于IDE代码语法检查、APT等。
- RetentionPolicy.CLASS - 在编译时由编译器保留在class文件中,但 Java 虚拟机(JVM)会忽略。应用于字节码操作,如AspectJ、热修复Roubust等。
- RetentionPolicy.RUNTIME - 标记的注解由 JVM 保留,因此运行时结合反射技术获取注解中的所有信息。比如早期的ButterKnife方案。
2. 应用实例
2.1 IDE代码语法检查应用实例
使用整型静态变量替换枚举类。编译器会为Enum类中每一项创建一个对象实例,赋值给我们定义枚举类型常量,并声明枚举对象数组来保存所有的枚举对象。每个整型静态变量占内存4字节,而枚举对象占用的内存:对象头(12)+对象引用(name,4)+索引(ordinal,4),除此之外还有数组,所以内存占用远大于静态变量。
结合@IntDef
自定义注解,减少内存占用。
@IntDef(value = {Demo.TYPE1, Demo.TYPE2})
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.SOURCE)
public @interface IType {
}
public final class Demo {
public static final int TYPE1 = 1;
public static final int TYPE2 = 2;
private void setType(@IType int type) {
````
}
}
2.2 APT
APT:“annotation processor tool”,注解处理器,用于处理注解。编写好的java源代码,经过javac的编译,变成jvm能够加载解析的字节码class文件。javac本身就自带apt,用来在编译器扫描处理注解信息。当然也可以为某些注解注册自己的注解处理器,注册的apt由javac调起,并将注解信息传递给注册的apt。在glide、butterknife、arouter、eventbus中都有应用。不过这些框架的注解大都是class级别。
推荐一个Java插件Lombok,可以自动实现数据bean的get、set、toString等方法。 原理也是使用apt。
参考ButterKnife源码,自己写一个,文章链接使用自定义注解自己实现ButterKnife功能 - 掘金 (juejin.cn)
2.3 字节码操作
直接修改字节码class文件,来达到修改代码执行逻辑的目的。比如运行期权限判定、代码中多次需要进行是否登陆的判断等。
字节码操作框架的作用在于生成或者修改Class文件,在Android中字节码框架本身是不需要打包进入APK的,
只有其生成/修改之后的Class才需要打包进入APK中。它的工作时机在Android打包流程中的生成Class之后,
打包dex之前。常见的字节码操作框架是ASM
,AspectJ
就是通过ASM
实现的。
ASM
可以直接从jcenter()仓库中引入
implementation "org.ow2.asm:asm:9.4"
实例todo