目录
一. 基本概念
Java 注解(Annotation)是一种元数据形式,提供关于程序代码的补充信息,但不会直接影响代码的执行。注解可以用于类、方法、变量、参数等元素,主要用于编译时检查、运行时反射或生成文档等场景。
二. 注解的核心作用
注解的核心价值在于提供元数据,主要应用场景包括:
- 编译期检查:如 @Override 确保方法正确重写父类方法,编译器会校验合法性。
- 生成文档:配合 Javadoc 工具,从注解中提取信息生成文档(如 @Deprecated 标记过时 API)。
- 运行时处理:框架(如 Spring、MyBatis)通过反射读取注解,动态执行逻辑(如@Autowired实现依赖注入)。
- 代码生成:通过 APT(Annotation Processing Tool)在编译期根据注解自动生成代码(如 Lombok 的@Data生成 getter/setter)。
三. 注解的分类
根据用途和来源,注解可分为三类:
1. 内置注解(JDK 自带)
JDK 提供了几个基础注解,用于常见场景:
@Override:标记方法重写父类或接口的方法。编译器会校验方法签名是否正确,若未正确重写则报错。
class Parent {
void doSomething() {}
}
class Child extends Parent {
@Override // 确保此方法正确重写父类
void doSomething() {}
}
@Deprecated:标记类、方法或字段已过时。编译器会对使用过时元素的代码发出警告,文档中也会标记 “过时” 说明。
@Deprecated
public class OldClass {} // 此类已过时
@SuppressWarnings:抑制编译器警告(如未使用变量、 unchecked 转换等)。需指定警告类型(如"unchecked"、“unused”)。
@SuppressWarnings("unused") // 抑制"变量未使用"的警告
int unusedVar = 10;
@SafeVarargs(Java 7+):标记方法的可变参数是类型安全的,抑制 “堆污染” 警告。@FunctionalInterface(Java 8+):标记接口为函数式接口(仅含一个抽象方法),编译器会校验合法性。
2. 元注解(修饰注解的注解)
元注解用于定义其他注解的行为(如注解可修饰的元素、保留周期等)。JDK 提供 4 个标准元注解:
| 元注解 | 作用 | 常用取值(ElementType) |
|---|---|---|
| @Target | 指定注解可应用的位置(如类、方法、字段等) | TYPE(类)、METHOD(方法)、FIELD(字段)等 |
| @Retention | 指定注解的保留阶段(源码、字节码、运行时) | RUNTIME(运行时可通过反射获取,最常用) |
| @Documented | 标记注解是否会被javadoc工具提取到文档中 | - |
| @Inherited | 标记注解是否可被子类继承(仅对类注解有效) | - |
@Target:指定注解可应用的元素类型(如类、方法、字段等)。取值来自ElementType枚举,常见值:
- TYPE:类、接口、枚举
- METHOD:方法
- FIELD:字段(成员变量)
- PARAMETER:方法参数
- CONSTRUCTOR:构造器
- LOCAL_VARIABLE:局部变量
示例:限制注解只能用于方法和字段
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface MyAnnotation {}
@Retention:指定注解的保留周期(即注解信息在哪个阶段有效)。取值来自RetentionPolicy枚举:
- SOURCE:仅在源码中保留,编译后丢弃(如@Override)。
- CLASS:保留到编译期(.class 文件中),但运行时不加载到 JVM(默认值)。
- RUNTIME:保留到运行时,可通过反射读取(如 Spring 的@Autowired)。
示例:注解保留到运行时
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}
@Documented:标记注解会被 Javadoc 工具提取到文档中(默认注解不会出现在文档里)。
@Inherited:标记注解可被子类继承(仅对类级注解有效)。即父类使用该注解,子类若未单独标注,也会继承父类的注解。
3. 自定义注解
开发者可根据需求定义自己的注解,需使用 @interface 关键字,并结合元注解指定其行为。
自定义注解的语法:
// 元注解:指定注解的保留周期和可修饰的元素
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
// 注解的"属性"(类似方法声明,可指定默认值)
String value() default "操作日志"; // value是特殊属性,使用时可省略属性名
boolean needLog() default true;
}
使用自定义注解:
public class UserService {
// 使用@Log注解,可指定属性值(value可省略属性名)
@Log("用户登录")
public void login(String username) {
// 业务逻辑
}
}
四、注解的解析
注解需要通过工具(编译器、APT、反射)解析才能发挥作用。解析方式分为两类:
1. 编译期解析(APT)
通过 Annotation Processing Tool 在编译期扫描注解,生成代码或进行校验(如 Lombok、ButterKnife)。
原理:自定义处理器实现 javax.annotation.processing.Processor 接口,在编译时读取注解信息并处理。
2. 运行时解析(反射)
若注解的 @Retention 为 RUNTIME ,可通过反射 API 在运行时获取注解信息并执行逻辑。
示例:解析 @Log 注解并打印日志
public class LogProcessor {
public static void process(Object obj) throws Exception {
// 获取类中所有方法
Method[] methods = obj.getClass().getMethods();
for (Method method : methods) {
// 判断方法是否有@Log注解
if (method.isAnnotationPresent(Log.class)) {
Log logAnnotation = method.getAnnotation(Log.class);
// 读取注解属性
String logInfo = logAnnotation.value();
boolean needLog = logAnnotation.needLog();
if (needLog) {
System.out.println("执行日志:" + logInfo);
}
}
}
}
// 测试
public static void main(String[] args) throws Exception {
UserService service = new UserService();
process(service); // 输出:执行日志:用户登录
}
}
五. 常见应用场景
- 框架配置(如 Spring 的
@Autowired、@Component)。 - 测试工具标记(如 JUnit 的
@Test)。 - 代码生成(如 Lombok 的
@Data)。 - 数据校验(如 Hibernate Validator 的
@NotNull)。 - 权限控制:自定义@RequiresPermission注解,拦截器解析并校验权限。
六.注意事项
- 注解的成员变量只能是基本类型、String、Class、枚举、注解或它们的数组。
- 默认值通过
default关键字指定。 - 运行时处理的注解需谨慎设计,避免性能开销。
通过合理使用注解,可以显著提升代码的可读性和可维护性,同时减少样板代码的编写。
1万+

被折叠的 条评论
为什么被折叠?



