文章目录
- [497. Java 反射 - 使用反射读取注解](#497. Java 反射 - 使用反射读取注解)
-
- [1. 为什么要关心注解?](#1. 为什么要关心注解?)
- [2. 获取注解的工具类:`AnnotatedElement`](#2. 获取注解的工具类:
AnnotatedElement) - [3. 示例:类级别注解](#3. 示例:类级别注解)
- [4. 示例:重复注解 (Repeatable Annotations)](#4. 示例:重复注解 (Repeatable Annotations))
-
- [方式一:通过容器注解 `@Validators`](#方式一:通过容器注解
@Validators) - [方式二:直接用 `getAnnotationsByType()`](#方式二:直接用
getAnnotationsByType())
- [方式一:通过容器注解 `@Validators`](#方式一:通过容器注解
- [5. 总结](#5. 总结)
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. 示例:类级别注解
定义枚举和注解:
java
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;
}
在类上使用:
java
@Serialized
@Bean
public class Person {}
通过反射读取:
java
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);
}
输出:
java
isBean = true
annotation = @org.devjava.Serialized(format=JSON)
annotation = @org.devjava.Bean()
👉 注意:返回的其实是注解类的实例对象,你可以直接调用它的方法。
java
Serialized serialized = c.getAnnotation(Serialized.class);
System.out.println("format = " + serialized.format());
输出:
java
format = JSON
4. 示例:重复注解 (Repeatable Annotations)
定义验证规则:
java
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 类的字段上:
java
public class Person {
@Validator(ValidationRules.NON_NULL)
@Validator(ValidationRules.NON_EMPTY)
private String name;
}
读取注解:
方式一:通过容器注解 @Validators
java
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);
}
输出:
java
validator = @org.devjava.Validator(NON_NULL)
validator = @org.devjava.Validator(NON_EMPTY)
方式二:直接用 getAnnotationsByType()
java
Validator[] validators = nameField.getAnnotationsByType(Validator.class);
for (Validator v : validators) {
System.out.println("annotation = " + v);
}
输出:
java
annotation = @org.devjava.Validator(NON_NULL)
annotation = @org.devjava.Validator(NON_EMPTY)
👉 第二种方式更简洁,JDK 会自动帮你展开容器注解。
5. 总结
- 注解是框架的"说明书",框架通过反射读取注解来决定如何运行。
- 类、方法、字段、构造函数 都可以携带注解,并通过
AnnotatedElement访问。 isAnnotationPresent():检查是否存在。getAnnotation():获取单个注解。getAnnotationsByType():用于重复注解。