Java 注解(Annotation)自 Java 5 引入以来,已成为现代 Java 开发中不可或缺的一部分。它们如同代码中的“标签”或“元数据”,为类、方法、字段等程序元素附加额外信息,从而被编译器、开发工具或运行时框架识别和处理。
从 @Override 到 Spring 的 @Autowired,注解极大地提升了代码的可读性、可维护性和开发效率。本文将带你系统掌握 Java 注解的核心概念、自定义方法、处理机制与典型应用场景。
一、什么是注解?代码的“元数据标签”1.1 初识注解Java 注解以 @注解名 的形式出现在代码中,附着于类、接口、方法、字段、参数等元素之上,用于描述这些元素的额外信息。
代码语言:java复制@Override
public String toString() {
return "User{}";
}这里的 @Override 并不是注释,而是一个编译器指令:它告诉编译器“这个方法是重写父类方法的”,如果父类没有该方法,编译将报错。
💡 注解本身不改变程序逻辑,但它可以影响程序的行为——通过编译器、工具或框架对它的“解读”。
二、注解的三大用途用途
说明
示例
编译器指令
指导编译器进行检查或警告
@Override, @SuppressWarnings
代码分析
工具通过注解生成文档、检查规范
@Documented, SonarQube 分析
运行时处理
框架在运行时读取注解并执行逻辑
Spring 的 @Autowired, JPA 的 @Entity
三、Java 内置注解一览Java 提供了多个常用内置注解,帮助开发者编写更安全、清晰的代码:
注解
作用
@Override
确保方法正确重写父类方法,防止拼写错误
@Deprecated
标记已过时的方法或类,建议不再使用
@SuppressWarnings
抑制编译器警告(如未使用变量、泛型不安全等)
@FunctionalInterface
确保接口是函数式接口(仅含一个抽象方法)
示例说明:代码语言:java复制@Deprecated(since = "1.8", forRemoval = true)
public void oldMethod() {
// 已废弃方法
}
@SuppressWarnings("unchecked")
public List
return (List
}✅ 使用 @Deprecated 时建议添加 since 和 forRemoval 属性,提高可维护性。
四、自定义注解:打造你的代码标记语言Java 允许我们定义自己的注解,为项目添加语义化标签。
4.1 定义一个自定义注解使用 @interface 关键字定义注解:
代码语言:java复制public @interface MyAnnotation {
String author() default "Anonymous";
int version() default 1;
String[] tags() default {};
}author, version, tags 是注解的成员(元素)可以设置 default 默认值使用时可省略有默认值的成员4.2 使用自定义注解代码语言:java复制@MyAnnotation(
author = "Zhang San",
version = 2,
tags = {"security", "core"}
)
public class UserService {
// ...
}五、元注解:控制注解的“规则”元注解(Meta-Annotation)是“注解的注解”,用于定义注解的行为和作用范围。
5.1 @Retention:注解的生命周期值
说明
RetentionPolicy.SOURCE
仅保留在源码中,编译后丢弃(如 @Override)
RetentionPolicy.CLASS
保留在 .class 文件中,但运行时不可见
RetentionPolicy.RUNTIME
保留在 .class 中,并可在运行时通过反射获取
✅ 框架常用 RUNTIME,如 Spring、JPA。
代码语言:java复制@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation { ... }5.2 @Target:注解的适用位置值
说明
ElementType.TYPE
类、接口、枚举
ElementType.METHOD
方法
ElementType.FIELD
字段
ElementType.PARAMETER
参数
ElementType.CONSTRUCTOR
构造器
ElementType.LOCAL_VARIABLE
局部变量
代码语言:java复制@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime { }5.3 其他常用元注解元注解
作用
@Documented
注解将包含在 Javadoc 文档中
@Inherited
子类可继承父类的注解
@Repeatable
允许在同一位置重复使用该注解
💡 @Repeatable 示例:
java深色版本@Repeatable(Schedules.class) public @interface Schedule { String time(); } @Schedule(time = "morning") @Schedule(time = "evening") public void dailyTask() { ... }
六、注解处理器:让注解“活”起来注解本身只是“静态标签”,要发挥其作用,必须通过注解处理器来解析和执行逻辑。
6.1 运行时处理:通过反射读取注解这是最常见的方式,适用于 Spring、MyBatis 等框架。
代码语言:java复制// 读取类上的注解
MyAnnotation classAnn = UserService.class.getAnnotation(MyAnnotation.class);
System.out.println("作者:" + classAnn.author());
System.out.println("版本:" + classAnn.version());
// 读取方法上的注解
Method method = UserService.class.getMethod("createUser");
if (method.isAnnotationPresent(LogExecutionTime.class)) {
System.out.println("该方法需要记录执行时间");
}✅ 前提:注解必须使用 @Retention(RUNTIME)。
6.2 编译期处理:APT(Annotation Processing Tool)APT 是在编译阶段处理注解的机制,常用于生成代码。
例如:Lombok 使用 APT 在编译时自动生成 getter、setter、toString 等方法。
自定义 APT 处理器步骤:实现 javax.annotation.processing.Processor 接口重写 process() 方法,扫描并处理目标注解使用 Filer 生成新的 Java 文件通过 META-INF/services/javax.annotation.processing.Processor 注册处理器🔍 APT 常用于 ORM 框架、Builder 模式代码生成等场景。
七、实战案例:自定义日志注解 + AOP 记录执行时间我们来实现一个 @LogExecutionTime 注解,自动记录方法执行耗时。
7.1 定义注解代码语言:java复制@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogExecutionTime {
}7.2 应用注解代码语言:java复制public class BusinessService {
@LogExecutionTime
public void processData() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("业务数据处理完成");
}
}7.3 使用动态代理 + 反射实现日志功能代码语言:java复制public class LogProxy implements InvocationHandler {
private final Object target;
public LogProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 检查是否有 @LogExecutionTime 注解
if (method.isAnnotationPresent(LogExecutionTime.class)) {
long start = System.currentTimeMillis();
System.out.println("⏰ 开始执行: " + method.getName());
Object result = method.invoke(target, args);
long end = System.currentTimeMillis();
System.out.println("✅ 执行结束: " + method.getName() + ", 耗时: " + (end - start) + "ms");
return result;
}
// 无注解,直接调用
return method.invoke(target, args);
}
}7.4 测试代码语言:java复制BusinessService service = new BusinessService();
BusinessService proxy = (BusinessService) Proxy.newProxyInstance(
service.getClass().getClassLoader(),
service.getClass().getInterfaces(),
new LogProxy(service)
);
proxy.processData();输出结果:代码语言:java复制⏰ 开始执行: processData
业务数据处理完成
✅ 执行结束: processData, 耗时: 204ms✅ 成功实现“无侵入式”性能监控!
八、注解的典型应用场景框架/工具
注解示例
功能
Spring
@Component, @Autowired, @RestController
依赖注入、AOP、Web 映射
JPA/Hibernate
@Entity, @Table, @Column
对象关系映射(ORM)
JUnit/TestNG
@Test, @Before, @After
标记测试方法
Lombok
@Getter, @Setter, @Data
自动生成样板代码
Swagger
@ApiOperation, @ApiModel
生成 API 文档
Validation
@NotNull, @Size
参数校验
九、使用注解的最佳实践命名清晰:注解名应表达明确语义,如 @Cacheable、@Transactional。合理使用 @Retention:运行时注解慎用,避免性能开销。避免过度使用:注解不是银弹,过多注解会降低代码可读性。结合文档:使用 @Documented 提升 API 可维护性。优先使用成熟框架注解:如 Spring、Jakarta EE 提供的标准注解。结语Java 注解是一种强大的元数据机制,它让代码具备了“自我描述”的能力。通过注解,我们可以实现:
更安全的编译检查更简洁的配置方式更灵活的框架扩展更高效的开发体验