1

03、注解是什么?——《Android打怪升级之旅》

 1 year ago
source link: https://blog.csdn.net/kuanggang_android/article/details/127244945
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2t1YW5nZ2FuZ19hbmRyb2lk,size_16,color_FFFFFF,t_70

感谢大家和我一起,在Android世界打怪升级!

注解非常的简单,但又大量的出现在源码中。希望通过该文章,能让大家看到注解不打怵,明白如何自定义注解,以及注解的作用,一眼就能粗略的理解该注解的原理。

一、注解是什么

注解(Annotation)是JDK1.5引入的注释机制,它本身没有任何意义,仅仅是对代码的注释,被修饰的代码不会被影响执行。

但是它和普通的代码注释又不同,可以保留在各个时间段(源码、字节码、运行时),在各个时间段通过不同的技术(APT、字节码增强、反射),做不同的事情。

举一个简单的例子:

@Override:检查该方法是否是重写方法,仅保留在源码阶段,编译时判断如果父类和接口中没有该方法,会报错。

二、自定义注解

咱们依然拿@Override注解举例,下面是它的源码

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

从上面代码我们看到了三个比较新的东西,@Target、@Retention、@interface,咱们一个个来说

2.1 关键字:@interface

类使用class关键字修饰、接口使用interface关键字修饰、注解使用 @interface 关键字修饰。

2.2 元注解:@Target

注解是用来注释代码的,而元注解是用来注释注解的,给自定义的注解增加一些限定范围。

@Target:元注解之一,限制注解的使用范围,比如作用在属性、方法还是类上。接收的是一个数组,可以指定多个范围。

可接收的范围:

public enum ElementType {
	// 类、接口(包括注释类型)或枚举
    TYPE,
	// 字段(包括枚举常量)
    FIELD,
	// 方法
    METHOD,
	// 参数
    PARAMETER,
	// 构造方法
    CONSTRUCTOR,
	// 局部变量
    LOCAL_VARIABLE,
	// 注释类型
    ANNOTATION_TYPE,
	// 包
    PACKAGE
}
newCodeMoreWhite.png
// 单个范围,@Override仅可用在方法上
@Target(ElementType.METHOD)
public @interface Override {
}

// 多个范围,@Test可使用在 构造方法 和 方法 上
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface Test {
}

2.3 元注解:@Retention

@Retention:元注解之一,保留级别,设置该注解代码可以保留到什么阶段。

可保留的阶段:

public enum RetentionPolicy {
	// 源码阶段,在编译阶段存留,在class字节码中会消除
    SOURCE,
    // 字节码阶段,在class字节码存留,在运行时消除
    CLASS,
    // 运行时阶段,最长的阶段,可以保留到虚拟机中
    RUNTIME
}
// @Override注解只能保存到源码阶段,在生成class字节码中消除
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

2.4 自定义注解:@Test

我们来实战一下,需求如下:

  1. 可以保留到字节码阶段
  2. 能作用在 字段 和 方法 上
  3. 可以接收字符串数组参数
// 注解定义
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
public @interface Test {
    String[] value();
}

// 使用
public class TestAnnotation {
    @Test("test")
    private String name;

    @Test({"test1", "test2"})
    public void test() {

    }
}
newCodeMoreWhite.png

三、注解的作用

文章的开头我们提到过,注解保留在各个时间段(源码、字节码、运行时),在各个时间段通过不同的技术(APT、字节码增强、反射),做不同的事情。

我们这里不对技术进行详解,只对其做个概述,大家知道能做什么即可,如果有兴趣可以去深入学习。

3.1 源码阶段 —— APT(注解处理器)

APT(Annotation Processing Tool),注解处理器,简单来说就是在编译时寻找被该注解注释的代码,获取注解上的信息,通过某种方式进行提醒或者生成Java代码(不能修改原代码,如:JavaPoet)。比如路由注解就是通过编译时生成代码统一注册的。

ButterKnife、EventBus、ARouter等框架用的都是该技术,但是大家更喜欢把保留级别指定在字节码和运行时,因为一定会包括源码阶段。

3.2 字节码阶段 —— 字节码增强

就是修改字节码,在生成的class字节码阶段,可以对当前被注释的方法进行修改增强。比如我们写一个@NeedLogin注释在一个需要登录的方法外面,在生成字节码后可以对该方法的前后进行字节码插入,以达到登录的目的。

// 初始代码
@NeedLogin
public void test() {
    System.out.println("你好");
}

// 被字节码增强后
public void test() {
    if (!isLogin) {
        // 打开登录页
        return;
    }
    System.out.println("你好");
}

3.3 运行时阶段 —— 反射

在运行时可以通过反射获取注解的信息和元素,根据这些可以做不同的逻辑判定。

最后咱们再总结一下注解的知识点:

  1. 注解是JDK1.5引入的注释机制,本身没有任何意义。
  2. 注解使用@interface关键字修饰,使用@Target指定限定范围(方法、属性等),使用@Retention指定保留阶段(源码、字节码、运行时)。
  3. 注解可以在源码阶段使用APT,在字节码阶段使用字节码增强,在运行时阶段使用反射。

这样注解的介绍就结束了,希望大家读完这篇文章,会对注解有一个更深入的了解。如果我的文章能给大家带来一点点的福利,那在下就足够开心了。

下次再见!
20210416223107931.jpg


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK