android 注解详解

1,注解的概念

注解现在广泛的应用于android的各个开源框架中,不理解注解,我们就无法更好的提升我们的架构能力。那么什么是注解呢?注解(Annotation),是JDK5.0 引入的一种注释机制。 注解是元数据的一种形式,提供有关于程序但不属于程序本身的数据。注解对它们注解的代码的操作没有直接影响。

2,注解的定义

在java中,所有的注解都默认实现Annotation接口,接口如下:

java 复制代码
public interface Annotation {
    boolean equals(Object var1);

    int hashCode();

    String toString();

    Class<? extends Annotation> annotationType();
}

要定义一个注解,和定义一个接口差不多,只不过在interface前面多了一个@

java 复制代码
public @interface YuanZhen{

}

3,元注解

在定义注解时,注解类也能够使用其他的注解声明。对注解类型进行注解的注解类,我们称之为 meta-annotation(元注解)

元注解有四种类型:

|-------------|---------------------------------|
| @Target | 指定注解的作用范围 |
| @Retention | 指定注解的作用时机 |
| @Inherited | 被该注解修饰的注解,作用在某个类上,该类的此注解可以被子类继承 |
| @Documented | 给Javadoc配置的 |
| @IntDef | android新引入的,int类型,代替枚举的使用 |
| @StringDef | android新引入的,String类型,代替枚举的使用 |

最常用的是@Target 和@Retention。@Inherited和@Documented 一般很少用到,@IntDef和@StringDef多用来代替枚举,因为枚举的使用会增加内存的消耗。

3.1 @Target

@Target用来指定注解的作用范围,参数如下:

|-----------------------------|-------------|
| ElementType.ANNOTATION_TYPE | 可以应用于注解类型 |
| ElementType.CONSTRUCTOR | 可以应用于构造函数 |
| ElementType.FIELD | 可以应用于字段或属性 |
| ElementType.LOCAL_VARIABLE | 可以应用于局部变量 |
| ElementType.METHOD | 可以应用于方法级注解 |
| ElementType.PACKAGE | 可以应用于包声明 |
| ElementType.PARAMETER | 可以应用于方法的参数 |
| ElementType.TYPE | 可以应用于类的任何元素 |

可以看一下下面的例子:

定义一个作用于方法参数的注解

java 复制代码
@Target(ElementType.PARAMETER)//作用于方法的参数
public @interface YuanZhen {
}

当作用于类上时,就会报错,而作用于方法参数上,就可以正常运行

3.2@Retention

此元注解用来指定注解的作用时机,也就是说注解是在什么阶段有效,参数如下:

|-------------------------|--------------------------------------|
| RetentionPolicy.SOURCE | 标记的注解仅保留在源级别中,并被编译器忽略 |
| RetentionPolicy.CLASS | 标记的注解在编译时由编译器保留,但 Java 虚拟机 (JVM) 会忽略 |
| RetentionPolicy.RUNTIME | 标记的注解由 JVM 保留,因此运行时环境可以使用它 |

3.2.1RetentionPolicy.SOURCE

源码级别,在编译期能够获取注解与注解声明的类包括类中所有成员信息,一般用于生成额外的辅助类。

这个最常用的技术就是APT技术,好多开源框架都是使用的这种技术,例如:ButterKnife,EventBus,ARout,IOC,ROOM等等,应用非常广泛,APT技术一般是结合JavaPoet使用,具体怎么使用,请参照android注解之APT和javapoet_袁震的博客-CSDN博客

3.2.2RetentionPolicy.CLASS

字节码级别,在编译出Class后,通过修改Class数据以实现修改代码逻辑目的。对于是否需要修改的区分或者修改为不同逻辑的判断可以使用注解。

这个最常用的技术就是字节码插桩,字节码插桩框架主要有三种,ASM,Javassist,AspectJ。

性能方面ASM最优。稳定性和简单性方面AspectJ最优。利用AOP思想,我们可以无侵入的实现埋点,监控方法耗时,UI卡顿监控,自动添加日志,代码隔离等等功能。以后有时间会讲解各个功能的实现方案。

3.2.3 RetentionPolicy.RUNTIME

上面两个都属于编译阶段,RetentionPolicy.RUNTIME属于运行时期,它是在程序运行期间,通过反射技术动态获取注解与其元素,从而完成不同的逻辑判定。

这个最典型的使用案例就是反射,关于反射相信大家都不陌生了。如果有不清楚反射的,可以看一下android反射详解_袁震的博客-CSDN博客

3.3@Inherited

该注解的作用是子类可以继承父类的注解,意思就是,如果一个注解添加了@Inherited,例如:

java 复制代码
@Inherited
@Target(ElementType.TYPE)
public @interface YuanZhen {
}

那么用该注解修饰的类,其子类可以获取到该注解。

3.4@IntDef 和@StringDef

@IntDef 和@StringDef是安卓引入的新的元注解,这两个注解的主要作用是用来替代枚举的,因为枚举对内存的消耗比较大,下面来看怎么使用:

自定义一个注解:

java 复制代码
@Inherited
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.SOURCE)
@IntDef({DataBean.DOCTOR, DataBean.TEACHER})
public @interface YuanZhen {
    
}

数据类:

java 复制代码
public class DataBean {

    public static final int DOCTOR = 0;

    public static final int TEACHER = 1;

    private int type;

    public void setType(@YuanZhen int type) {
        this.type = type;
    }

    public int getType() {
        return type;
    }
}

使用时:

@StringDef和@IntDef的用法一样,这里就不再举例了。

4,注解类型元素

注解允许我们在使用时传递参数,可以传递一个参数或者多个参数

当只有一个参数需要传递时,我们可以这样写:

java 复制代码
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface YuanZhen {

    String value() default "111";

}
java 复制代码
@YuanZhen("222")
public void testMethod(){
}
//因为有默认值 也可以这样写
@YuanZhen()
public void testMethod(){
}

注意:在使用注解时,如果定义的注解中的类型元素无默认值,则必须进行传值。
当有多个参数时,可以这样写:

java 复制代码
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface YuanZhen {

    String value() default "111";
    
    int age();

}
java 复制代码
@YuanZhen(value = "222",age = 88)
public void testMethod(){
}

5,总结

关于注解的基本知识就是这些,基本的注解并不难掌握,但是后面想要提高自己的架构能力,就必须结合APT,JavaPoet以及字节码插桩技术和反射,综合运用到框架中去,这并不是一件简单的事情,但是了解之后,我们就会发现一片新的天地。

相关推荐
武子康14 分钟前
大数据-230 离线数仓 - ODS层的构建 Hive处理 UDF 与 SerDe 处理 与 当前总结
java·大数据·数据仓库·hive·hadoop·sql·hdfs
武子康16 分钟前
大数据-231 离线数仓 - DWS 层、ADS 层的创建 Hive 执行脚本
java·大数据·数据仓库·hive·hadoop·mysql
苏-言22 分钟前
Spring IOC实战指南:从零到一的构建过程
java·数据库·spring
界面开发小八哥29 分钟前
更高效的Java 23开发,IntelliJ IDEA助力全面升级
java·开发语言·ide·intellij-idea·开发工具
草莓base43 分钟前
【手写一个spring】spring源码的简单实现--容器启动
java·后端·spring
Dnelic-1 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记
Allen Bright1 小时前
maven概述
java·maven
编程重生之路1 小时前
Springboot启动异常 错误: 找不到或无法加载主类 xxx.Application异常
java·spring boot·后端
薯条不要番茄酱1 小时前
数据结构-8.Java. 七大排序算法(中篇)
java·开发语言·数据结构·后端·算法·排序算法·intellij-idea
努力进修1 小时前
“探索Java List的无限可能:从基础到高级应用“
java·开发语言·list