1、注解的定义
首先看看ButterKnife的Bind注解的源码。
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD)
public @interface Bind{
@IdRes int[] value();
}
特点:
通过@interface进行申明。
---------------------------------------------
2、自定义注解
@Retention(RetentionPolicy.RUNTIME)//运行时
@Target({ElementType.TYPE,ElementType.FIELD})//作用目标
public @interface Test {
}
其中:@Retention 和 @Target 为元注解。
---------------------------------------------
3、Retention的取值如下:
RetentionPolicy.SOURCE
标记的注解仅保留在源级别中,并被编译器忽略。
RetentionPolicy.CLASS
标记的注解在编译时由编译器保留,但 Java 虚拟机(JVM)会忽略。
RetentionPolicy.RUNTIME
标记的注解由 JVM 保留,因此运行时环境可以使用它。
---------------------------------------------
4、这3个注解有什么应用场景?
1、源码(SOURCE)
使用的技术:APT
介绍:在编译期能够获取注解与注解声明的类包括类中所有成员信息,一般用于生成额外的辅助类。 比如GreenDao,ButterKnife,Arouter
扩展:APT的原理是什么?
2、字节码(CLASS)
使用到的技术:字节码增强
在编译出Class后,通过修改Class数据以实现修改代码逻辑目的。对于是否需要修改的区分或者修改为不同逻辑的判断可以使用注解。
3、运行时
反射
在程序运行期间,通过反射技术动态获取注解与其元素,从而完成不同的逻辑判定。
----------------------------------------------
5、应用:注解用于限定参数。
需求:需要限定方法的参数为固定的值,比如只能传递1、2、3这样的3个值。
如何实现:
(1)采用枚举的方式进行实现。
缺点:
1、每一个枚举都是一个对象,增加额外的内存消耗。
2、较多的使用枚举会增加DEX文件的大小。
(2)采用注解的方式进行实现。
实现方式如下:
第一步:定义所有的取值。
public class CategoryValue {
public static final int ALL = 1;//所有品种
public static final int WATER = 2;//水
public static final int FRUIT = 3;//水果
}
第二步:定义注解
// 告诉Category只能取这样的3个值
@IntDef(value = {CategoryValue.ALL, CategoryValue.WATER, CategoryValue.FRUIT})
@Retention(RetentionPolicy.RUNTIME) // 运行时
@Target({ElementType.TYPE, ElementType.PARAMETER}) // 作用目标
public @interface Category {
}
第三步:使用
public class Test {
public void test() {
test(CategoryValue.ALL);
// test(2); 如果直接传值,会出现编译错误
}
public void test(@Category int x) {
// 根据x处理对应的逻辑
}
}