注解(Annotation) 就像代码里的「便利贴」,用来给类、方法、字段等贴标签,告诉编译器、工具或运行时环境一些额外信息。它本身不改变代码逻辑,但可以通过其他工具读取这些标签来触发特定行为。
一、注解的三大作用
-
给编译器发指令
-
例子:
@Override -
作用:检查方法是否真的重写了父类方法,没重写就报错。
-
代码示例:
@Override public String toString() { return "重写成功"; }
-
-
给工具/框架发信号
-
例子:
@Test(JUnit)、@Autowired(Spring) -
作用:告诉测试框架“这是测试方法”,或让Spring自动注入依赖。
-
代码示例:
@Test public void testLogin() { /* 测试代码 */ }
-
-
生成代码或配置文件
-
例子:Lombok的
@Data -
作用:编译时自动生成getter/setter方法。
-
代码示例:
@Data public class User { private String name; private int age; }
-
二、注解的本质与定义
1. 注解的本质
-
注解是一个接口,继承自
java.lang.annotation.Annotation。 -
定义方式:用
@interface关键字。public @interface MyAnnotation { String value() default ""; // 参数(类似方法) int priority() default 0; }
2. 元注解(注解的注解)
| 元注解 | 作用 | 示例 |
|---|---|---|
@Target | 指定注解能贴在哪里 | @Target(ElementType.METHOD) |
@Retention | 指定注解保留到哪个阶段 | @Retention(RetentionPolicy.RUNTIME) |
@Documented | 让注解出现在Javadoc中 | @Documented |
@Inherited | 允许子类继承父类的注解 | @Inherited |
示例:定义一个运行时生效的类注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String name() default ""; // 数据库表名
}
三、注解的读取与处理
1. 编译时处理
-
APT(Annotation Processing Tool) :在编译时扫描注解,生成代码或报告。
- 例子:Lombok生成getter/setter。
2. 运行时处理
-
反射机制:通过反射API读取注解信息。
Class<?> clazz = User.class; if (clazz.isAnnotationPresent(Table.class)) { Table table = clazz.getAnnotation(Table.class); System.out.println("表名:" + table.name()); }
3. 框架集成
- Spring:
@Component注解标记Bean,容器启动时扫描并管理。 - JUnit:
@Test标记测试方法,运行时执行测试。
四、常见注解场景
| 场景 | 常用注解 | 作用 |
|---|---|---|
| 代码检查 | @Override, @Deprecated | 编译器检查或标记过时代码 |
| 依赖注入 | @Autowired, @Resource | Spring自动装配Bean |
| Web开发 | @Controller, @RequestMapping | Spring MVC处理HTTP请求 |
| 数据校验 | @NotNull, @Size | Hibernate校验字段合法性 |
五、总结口诀
「注解就像便利贴,贴在代码传信息
编译检查靠元注,运行时用反射读
框架工具认标签,自动生成少写码!」
附:自测问题
-
如何定义一个只能用在方法上、且在运行时有效的注解?
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface LogExecutionTime {} -
如何通过反射获取类上的注解?
Class<?> clazz = MyClass.class; MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class);