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以及字节码插桩技术和反射,综合运用到框架中去,这并不是一件简单的事情,但是了解之后,我们就会发现一片新的天地。

相关推荐
姑苏风41 分钟前
《Kotlin实战》-附录
android·开发语言·kotlin
魔道不误砍柴功2 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2342 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨2 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
测开小菜鸟3 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
数据猎手小k4 小时前
AndroidLab:一个系统化的Android代理框架,包含操作环境和可复现的基准测试,支持大型语言模型和多模态模型。
android·人工智能·机器学习·语言模型
P.H. Infinity4 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天4 小时前
java的threadlocal为何内存泄漏
java
caridle4 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
^velpro^5 小时前
数据库连接池的创建
java·开发语言·数据库