注解及在项目中的使用

76 阅读2分钟

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处理对应的逻辑
    }
}