497. Java 反射 - 使用反射读取注解

497. Java 反射 - 使用反射读取注解

1. 为什么要关心注解?

在现代 Java 开发中,注解已经成为框架和库的“开关”。

  • ORM 框架(如 Hibernate、JPA):用注解标记实体字段和表的映射。
  • Spring:用注解实现依赖注入、事务管理、安全控制。
  • 验证框架:用注解标记参数是否允许 null、是否必须符合某种格式。

👉 注解之所以能发挥作用,核心原因就是:运行时通过反射 API 读取注解并执行相应逻辑


2. 获取注解的工具类:AnnotatedElement

以下几个反射类都实现了 AnnotatedElement 接口:

  • Class(类、接口、枚举、记录、数组)
  • Field(字段)
  • Method(方法)
  • Constructor(构造函数)

它们提供了几组关键方法:

  • isAnnotationPresent(Class<?>):是否存在某个注解。
  • getAnnotations():获取该元素上的所有注解(包括继承的)。
  • getDeclaredAnnotations():只获取该元素本身声明的注解。
  • getAnnotation(Class<?>):获取指定类型的注解实例。
  • getAnnotationsByType(Class<?>):获取重复注解。

3. 示例:类级别注解

定义枚举和注解:

enum SerializedFormat { BINARY, XML, JSON }

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Bean {}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Serialized {
    SerializedFormat format() default SerializedFormat.JSON;
}

在类上使用:

@Serialized
@Bean
public class Person {}

通过反射读取:

Class<?> c = Person.class;

boolean isBean = c.isAnnotationPresent(Bean.class);
System.out.println("isBean = " + isBean);

Annotation[] annotations = c.getAnnotations();
for (Annotation annotation : annotations) {
    System.out.println("annotation = " + annotation);
}

输出:

isBean = true
annotation = @org.devjava.Serialized(format=JSON)
annotation = @org.devjava.Bean()

👉 注意:返回的其实是注解类的实例对象,你可以直接调用它的方法。

Serialized serialized = c.getAnnotation(Serialized.class);
System.out.println("format = " + serialized.format());

输出:

format = JSON

4. 示例:重复注解 (Repeatable Annotations)

定义验证规则:

enum ValidationRules { NON_NULL, NON_EMPTY, NON_ZERO }

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Validators {
    Validator[] value();
}

@Target(ElementType.FIELD)
@Repeatable(Validators.class)
@interface Validator {
    ValidationRules value();
}

应用在 Person 类的字段上:

public class Person {
    @Validator(ValidationRules.NON_NULL)
    @Validator(ValidationRules.NON_EMPTY)
    private String name;
}

读取注解:

方式一:通过容器注解 @Validators

Field nameField = Person.class.getDeclaredField("name");
Annotation[] annotations = nameField.getAnnotations();
Validators validators = (Validators) annotations[0];
for (Validator v : validators.value()) {
    System.out.println("validator = " + v);
}

输出:

validator = @org.devjava.Validator(NON_NULL)
validator = @org.devjava.Validator(NON_EMPTY)

方式二:直接用 getAnnotationsByType()

Validator[] validators = nameField.getAnnotationsByType(Validator.class);
for (Validator v : validators) {
    System.out.println("annotation = " + v);
}

输出:

annotation = @org.devjava.Validator(NON_NULL)
annotation = @org.devjava.Validator(NON_EMPTY)

👉 第二种方式更简洁,JDK 会自动帮你展开容器注解。


5. 总结

  • 注解是框架的“说明书”,框架通过反射读取注解来决定如何运行。
  • 类、方法、字段、构造函数都可以携带注解,并通过 AnnotatedElement 访问。
  • isAnnotationPresent():检查是否存在。
  • getAnnotation():获取单个注解。
  • getAnnotationsByType():用于重复注解。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容