Java

Java

注解的定义 & 作用

概念

注解(Annotation)是 JDK 1.5 新增特性,属于一种特殊标记注释,用来修饰类、方法、成员变量、参数、构造器等,在编译阶段 / 运行阶段被程序读取并解析使用。 分为两类:

  1. JDK 内置注解:@Override、@Deprecated、@WebServlet 等;
  2. 开发者自定义注解。

注解生效的两种解析方式

注解本身只是标记,必须被解析才能发挥作用:

  1. 编译期扫描解析 编译器编译代码时识别注解并处理。 例:@Override,编译阶段校验该方法是否正确重写了父类方法,写错直接编译报错。
  2. 运行期反射解析 框架主流方式(Spring @Component、@Value、MyBatis 注解等),程序运行时利用反射读取注解上的配置信息并执行逻辑。

注解两大核心作用

  1. 告知编译器语法校验规则;
  2. 替代传统 XML/Properties 配置文件,简化配置(SSM、SpringBoot 核心思想)。

内置注解示例

// 校验是否重写父类方法
@Override
public String toString() {
    return super.toString();
}

// Servlet注解,替代web.xml配置
@WebServlet("/student")
public class StudentServlet extends HttpServlet {
}

自定义注解

自定义注解可以在类、字段、方法上附加自定义配置信息,搭配反射读取注解数据。

元注解(修饰注解的注解)

用来规定「自定义注解能写在哪些位置」「存活到哪个阶段」。

@Target:限定注解的生效位置

@Target({
    TYPE,           // 类、接口、枚举
    FIELD,          // 成员字段
    METHOD,         // 普通方法
    PARAMETER,      // 方法形参
    CONSTRUCTOR,    // 构造方法
    LOCAL_VARIABLE  // 局部变量
})

@Retention:限定注解生命周期(存活阶段)

@Retention(RetentionPolicy.SOURCE)    // 仅源码阶段存在,编译成class后丢弃
@Retention(RetentionPolicy.CLASS)      // 保存到class字节码,运行时JVM丢弃(默认生命周期)
@Retention(RetentionPolicy.RUNTIME)   // 运行时期依旧保留,可以通过反射获取(框架自定义注解必选)

完整自定义注解案例

步骤1:定义注解 @Author

import java.lang.annotation.*;

// 该注解可以标注在类、成员变量、方法上
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
// 运行时保留,支持反射读取
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
    // 注解属性,可设置默认值
    String name() default "";

    int age() default 20;

    // 特殊属性名 value:使用注解时,如果只赋值value,可以省略value=
    String[] value() default {};
}

步骤2:使用自定义注解

// 完整赋值写法
@Author(name = "zhao", age = 12, value = "男")
public class AuthorDemo {

    // 全部使用默认属性值
    @Author
    private String str;

    @Author(name = "zhangsan", age = 23, value = {"男", "女"})
    public void add() {
    }
}

简写规则:注解只有 value 一个属性时,赋值可省略 value=

@Author("男")
// 等价
@Author(value = "男")

// 数组写法
@Author({"男", "女"})

步骤3:通过反射解析注解(读取注解中的数据)

import org.junit.Test;
import java.lang.reflect.Method;
import java.util.Arrays;

public class TestAnnotation {
    @Test
    public void test1() throws NoSuchMethodException {
        // 1. 获取类Class对象
        Class<AuthorDemo> clazz = AuthorDemo.class;

        // 2. 获取标注在类上的 @Author 注解
        Author typeAuthor = clazz.getAnnotation(Author.class);
        System.out.println(typeAuthor.value()[0]);

        // 3. 获取add方法对应的Method对象
        Method method = clazz.getDeclaredMethod("add");
        // 4. 获取方法上的注解
        Author methodAuthor = method.getAnnotation(Author.class);

        System.out.println(methodAuthor.name());         // zhangsan
        System.out.println(methodAuthor.age());           // 23
        System.out.println(Arrays.toString(methodAuthor.value())); // [男, 女]
    }
}

补充规则

  1. 自定义注解内可以定义多个属性,属性可以添加 default 默认值;
  1. 注解生命周期想要被反射读取,必须设置 @Retention(RetentionPolicy.RUNTIME);
  1. getAnnotation(注解.class):获取目标上指定类型注解,返回注解实例;
  1. 元注解就是修饰注解的注解,用来定义注解:
元注解 作用
@Target 指定注解可以用在什么地方:TYPE(类)、FIELD(字段)、METHOD(方法)、PARAMETER(参数)、CONSTRUCTOR(构造)
@Retention 指定注解保留到什么时候:SOURCE(编译丢弃)、CLASS(编译保留不加载)、RUNTIME(运行保留,可以反射读取)
@Documented 注解信息会被 javadoc 提取,生成 JavaDoc 文档时保留注解
@Inherited 修饰的注解会被子类继承
上一篇
下一篇