注解
约 868 字大约 3 分钟
布欧-Lewyon
2026-05-16
注解(Annotation)是 Java 5 引入的元数据机制,允许在代码中嵌入声明式信息,供编译器、框架或运行时工具读取处理。Spring 的 @Autowired、JUnit 的 @Test、Lombok 的 @Data 都是注解的典型应用。
内置注解
Java 标准库提供了一批内置注解,主要用于编译期检查和声明:
@Override // 标记方法重写,编译器检查签名是否匹配
@Deprecated // 标记已废弃,使用时会显示警告
@SuppressWarnings("unchecked") // 压制特定警告
@FunctionalInterface // 标记函数式接口(只能有一个抽象方法)自定义注解
使用 @interface 关键字定义注解:
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) // 运行时保留(可通过反射读取)
@Target(ElementType.METHOD) // 只能用在方法上
public @interface Loggable {
String value() default ""; // 注解属性
Level level() default Level.INFO;
}
enum Level { DEBUG, INFO, WARN, ERROR }使用自定义注解:
public class OrderService {
@Loggable(level = Level.WARN)
public void cancelOrder(long orderId) {
// 业务逻辑
}
@Loggable("创建订单") // value 属性可省略属性名
public void createOrder() { }
}- 注解属性声明像方法:
类型 属性名() default 默认值; value属性有特殊地位:赋值时可省略value=。- 属性类型限制:基本类型、
String、Class、enum、注解及其数组。
元注解
元注解是修饰注解的注解,控制自定义注解的行为:
| 元注解 | 作用 | 常用值 |
|---|---|---|
@Retention | 注解保留策略 | SOURCE(源码,编译丢弃)、CLASS(字节码,运行时不可反射)、RUNTIME(运行时保留,可反射读取) |
@Target | 注解可应用的 Java 元素 | TYPE、METHOD、FIELD、PARAMETER、CONSTRUCTOR、ANNOTATION_TYPE、PACKAGE |
@Documented | 注解出现在 Javadoc 中 | |
@Inherited | 注解被子类继承 |
@Retention(RetentionPolicy.RUNTIME) // 框架用注解通常选 RUNTIME
@Target(ElementType.FIELD) // 只能标注在字段上
public @interface NotNull {
String message() default "字段不能为空";
}反射读取注解
注解如果在 RUNTIME 保留,可通过反射读取(框架的底层机制):
// 模拟简单校验框架
public class Validator {
public static void validate(Object obj) throws IllegalAccessException {
for (Field field : obj.getClass().getDeclaredFields()) {
NotNull annotation = field.getAnnotation(NotNull.class);
if (annotation != null) {
field.setAccessible(true);
if (field.get(obj) == null) {
throw new RuntimeException(annotation.message());
}
}
}
}
}public class User {
@NotNull(message = "用户名不能为空")
private String name;
@NotNull
private String email;
}常用反射 API:
// 判断是否有注解
cls.isAnnotationPresent(MyAnnotation.class);
// 获取方法上的注解
Method method = cls.getMethod("someMethod");
MyAnnotation anno = method.getAnnotation(MyAnnotation.class);
// 获取所有注解
Annotation[] annotations = method.getAnnotations();注解的实际应用
注解在 Java 生态中被广泛用于替代 XML 配置和标记式编程:
- Spring:
@Component、@Service、@Autowired、@Transactional - JUnit:
@Test、@BeforeEach、@ParameterizedTest - Jakarta EE:
@Resource、@PostConstruct、@PreDestroy - Lombok:
@Data、@Slf4j、@Builder - Jackson:
@JsonProperty、@JsonIgnore
小结
- 注解是用
@interface声明的元数据,@Retention决定保留策略,@Target决定使用位置。 - 框架用注解通常设
RetentionPolicy.RUNTIME,配合反射在运行时读取。 - 内置注解
@Override、@Deprecated、@SuppressWarnings由编译器处理,保留在SOURCE。 value属性赋值时可省略属性名;属性类型只能是基本类型、String、Class、enum、注解及数组。- 易错:注解属性不能为
null,默认值必须是非null的常量表达式。此外,@Inherited只对类的继承有效,对接口的implements和方法重写无效。 - 思考任务:定义一个
@MaxLength(length = 10)注解,然后用反射实现一个字符串截断工具:标注了@MaxLength的字符串字段在赋值时自动截断到指定长度。
上一节:序列化
