菜鸟笔记
提升您的技术认知

注解是什么?-ag真人游戏

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

一、注解是什么

注解(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
}

举例:

// 单个范围,@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() {
  
    }
}

三、注解的作用

文章的开头我们提到过,注解保留在各个时间段(源码、字节码、运行时),在各个时间段通过不同的技术(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,在字节码阶段使用字节码增强,在运行时阶段使用反射。

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

网站地图