Skip to content

元注解

元注解是「注解的注解」——用来标注其他注解,控制它们的行为。Java 提供了五个标准元注解。

五个元注解一览

元注解作用
@Retention注解保留到哪个阶段(源码/编译/运行)
@Target注解可以用在哪些元素上
@Documented注解是否包含在 Javadoc 中
@Inherited注解是否被子类继承
@Repeatable注解是否可以重复使用

@Retention:保留策略

这是最重要的元注解,决定了注解的生命周期:

策略说明典型用途
SOURCE只存在于源码,编译后丢弃@Override@SuppressWarnings
CLASS存在于 .class 文件,JVM 加载时不保留编译时注解处理器(如 Lombok)
RUNTIME存在于运行时,可通过反射获取Spring 依赖注入、JUnit 测试
java
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

// 源码保留(默认):编译后丢弃
@Retention(RetentionPolicy.SOURCE)
public @interface SourceOnly { }

// CLASS 保留:编译时保留,运行时丢弃
@Retention(RetentionPolicy.CLASS)
public @interface ClassOnly { }

// RUNTIME 保留:运行时可见,反射可读取
@Retention(RetentionPolicy.RUNTIME)
public @interface RuntimeOnly { }

@Target:使用范围

控制注解可以用在哪些代码元素上:

ElementType说明
TYPE类、接口、枚举
METHOD方法
FIELD字段
PARAMETER方法参数
CONSTRUCTOR构造方法
LOCAL_VARIABLE局部变量
ANNOTATION_TYPE注解类型
java
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

// 只能用于方法
@Target(ElementType.METHOD)
public @interface MethodAnnotation { }

// 可用于多种元素
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
public @interface MultiAnnotation { }

@Documented:包含在 Javadoc 中

默认情况下,注解不会出现在 Javadoc 中。加上 @Documented 后会包含:

java
import java.lang.annotation.Documented;

@Documented
public @interface DocumentedAnnotation {
    String value();
}

// 使用此注解的代码生成的 Javadoc 会包含这个注解信息

@Inherited:子类继承

如果父类标注了 @Inherited 注解,子类会自动继承该注解:

java
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Inherited  // 子类会继承此注解
public @interface InheritedAnnotation {
    String value();
}

@InheritedAnnotation("parent")
class Parent { }

class Child extends Parent { }  // 自动继承 @InheritedAnnotation

public class InheritedDemo {
    public static void main(String[] args) {
        // Child 类继承了父类的注解
        if (Child.class.isAnnotationPresent(InheritedAnnotation.class)) {
            InheritedAnnotation ann = Child.class.getAnnotation(InheritedAnnotation.class);
            System.out.println(ann.value());  // parent
        }
    }
}

注意:@Inherited 只对类级别的注解生效,对方法注解无效。

@Repeatable:可重复注解(JDK 8+)

JDK 8 之前,同一个注解不能重复使用。@Repeatable 解决了这个问题:

java
import java.lang.annotation.*;

// 1. 定义基础注解
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Authors.class)  // 指定容器注解
public @interface Author {
    String name();
}

// 2. 定义容器注解(名字必须以复数形式结尾)
@Retention(RetentionPolicy.RUNTIME)
public @interface Authors {
    Author[] value();
}

// 3. 使用:同一个注解可以写多次
@Author(name = "张三")
@Author(name = "李四")
public class Book {
    public static void main(String[] args) {
        // 获取所有 @Author 注解
        Author[] authors = Book.class.getAnnotationsByType(Author.class);
        for (Author author : authors) {
            System.out.println(author.name());
        }
    }
}

综合示例

java
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
public @interface Documentation {
    String value() default "";
    String author() default "Unknown";
}

@Documentation(value = "用户服务类", author = "张三")
public class UserService {

    @Documentation("用户登录方法")
    public void login() { }
}

注意事项

  1. @Retention 是最重要的元注解:如果设置为 SOURCE,运行时反射无法获取
  2. @Target 可以指定多个值:用数组形式 {ElementType.TYPE, ElementType.METHOD}
  3. @Inherited 只对类生效:方法、字段的注解不会被继承
  4. @Repeatable 需要容器注解:必须配套定义一个「容器」注解

基于 VitePress 构建