Skip to content

自定义注解

注解本质上是一个继承了 java.lang.annotation.Annotation 接口的接口。定义注解和定义接口类似,但要用 @interface 关键字。

基本语法

java
// 定义注解
@Retention(RetentionPolicy.RUNTIME)  // 运行时保留
@Target(ElementType.METHOD)          // 只用于方法
public @interface MyAnnotation {
    // 注解属性(本质上是一个抽象方法)
    String value() default "";      // 有默认值,使用时可省略
    String name();                 // 无默认值,使用时必须指定
    int[] numbers() default {};    // 数组属性
}

代码示例

基本注解

java
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Todo {
    String value() default "";
    Priority priority() default Priority.MEDIUM;
}

enum Priority {
    LOW, MEDIUM, HIGH
}

class Task {
    @Todo(value = "完成用户认证", priority = Priority.HIGH)
    public void authenticate() {}

    @Todo("添加日志记录")  // value 属性可省略名称
    public void process() {}
}

带多个属性的注解

java
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Entity {
    String tableName();
    String primaryKey() default "id";
    boolean autoGeneratePK() default true;
}

@Entity(tableName = "users", autoGeneratePK = true)
class User {}

属性类型限制

注解属性只能是以下类型:

  • 基本类型(intlongboolean 等)
  • String
  • ClassClass<?>(带泛型)
  • 枚举类型
  • 以上类型的数组
java
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ComplexAnnotation {
    String message();                    // ✅ String
    int count();                         // ✅ 基本类型
    Class<?> clazz();                    // ✅ Class
    Priority priority();                 // ✅ 枚举
    String[] tags();                     // ✅ 数组
    Class&lt;?&gt;[] dependencies();          // ✅ Class 数组
}

注解的属性本质

注解中的属性定义,实质上就是抽象方法

java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Author {
    // 这其实是一个抽象方法
    // 返回类型是 String,默认值是空字符串
    String value() default "";
}

// 使用时,其实是在给属性赋值
@Author("张三")  // 相当于调用 value() 方法,传入 "张三"

使用时的省略规则

  • 如果只有一个属性叫 value,使用时可省略属性名
  • 如果属性是数组类型,且只赋值一个元素,可以省略 {}
java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
    String value() default "";
    int priority() default 0;
}

// ✅ 省略属性名(只有一个 value)
@Test("测试用例1")

// ✅ 显式指定属性名
@Test(value = "测试用例2", priority = 1)

// ✅ 数组只有一个元素,省略 {}
@Test({"test1"})  // 或者 @Test("test1")

注解处理器

定义注解后,可以通过反射读取注解信息:

java
import java.lang.reflect.*;

public class AnnotationProcessor {

    public static void main(String[] args) {
        // 读取类上的注解
        if (User.class.isAnnotationPresent(Entity.class)) {
            Entity entity = User.class.getAnnotation(Entity.class);
            System.out.println("Table: " + entity.tableName());
            System.out.println("PK: " + entity.primaryKey());
        }

        // 读取方法上的注解
        for (Method method : Task.class.getDeclaredMethods()) {
            if (method.isAnnotationPresent(Todo.class)) {
                Todo todo = method.getAnnotation(Todo.class);
                System.out.println("Todo: " + todo.value() +
                    " (Priority: " + todo.priority() + ")");
            }
        }
    }
}

注意事项

  1. 注解属性不能是对象引用:只能是基本类型、String、Class、枚举及其数组
  2. 提供默认值:非必需的属性应该提供 default,避免使用时必须指定
  3. 命名规范:注解属性名通常用名词或动词不定式(如 valueauthorsince
  4. 反射前提@Retention 必须设置为 RUNTIME,反射才能读取

基于 VitePress 构建