Java 注解(Annotation)详解
一、注解是什么?
注解(Annotation) 是 Java 提供的一种元数据机制,用于为代码附加额外信息。这些信息可以被编译器、开发工具或运行时框架读取,并根据注解内容执行特定操作。
类比:注解就像是代码的“标签”,告诉计算机如何处理被标注的代码。
常见内置注解:
@Override
:标记方法重写父类方法。@Deprecated
:标记方法或类已过时。@SuppressWarnings
:抑制编译器警告。
二、如何定义注解?
通过 @interface
关键字定义注解,并使用元注解(Meta-Annotation) 控制注解的行为。
1. 定义注解示例
import java.lang.annotation.*;
// 元注解:定义注解的保留策略和目标
@Retention(RetentionPolicy.RUNTIME) // 注解在运行时保留
@Target(ElementType.METHOD) // 注解只能用于方法
public @interface MyAnnotation {
String value() default "默认值"; // 注解参数(类似方法)
int priority() default 1; // 可定义多个参数
}
2. 元注解详解
元注解 | 作用 | 示例 |
---|---|---|
@Retention | 指定注解保留的生命周期: | @Retention(RetentionPolicy.RUNTIME) |
- SOURCE :仅保留在源码中(如 @Override )。 | ||
- CLASS :保留到字节码,但运行时不可见。 | ||
- RUNTIME :运行时保留(可通过反射读取)。 | ||
@Target | 指定注解可以应用的位置: | @Target({ElementType.METHOD, ElementType.TYPE}) |
- TYPE :类/接口/枚举 | ||
- FIELD :字段 | ||
- METHOD :方法 | ||
- PARAMETER :方法参数 | ||
@Documented | 标注的注解会被包含在 Javadoc 中。 | @Documented |
@Inherited | 允许子类继承父类的注解(默认不继承)。 | @Inherited |
三、如何使用注解?
1. 基本使用
直接在代码元素(类、方法、字段等)上添加注解:
// 类上使用注解
@MyAnnotation(value = "类注解", priority = 2)
public class MyClass {
// 方法上使用注解
@MyAnnotation("方法注解")
public void myMethod() {
// ...
}
}
2. 注解参数规则
- 若注解仅有一个参数且名为
value
,可省略参数名:@MyAnnotation("直接赋值value")
- 参数可以是基本类型、String、枚举、Class、其他注解或它们的数组:
public @interface ComplexAnnotation { String[] tags(); Class<?> targetClass(); RetentionPolicy policy() default RetentionPolicy.RUNTIME; } // 使用示例 @ComplexAnnotation( tags = {"java", "annotation"}, targetClass = MyClass.class ) public void complexMethod() {}
四、注解的处理
1. 编译时处理
通过 APT(Annotation Processing Tool) 或 Lombok 在编译时生成代码:
- 示例:Lombok 的
@Data
自动生成 getter/setter。
2. 运行时处理
通过 反射(Reflection) 读取运行时注解,并执行逻辑:
public class AnnotationProcessor {
public static void main(String[] args) {
Class<MyClass> clazz = MyClass.class;
// 读取类上的注解
MyAnnotation classAnnotation = clazz.getAnnotation(MyAnnotation.class);
System.out.println("类注解值: " + classAnnotation.value());
// 读取方法上的注解
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation methodAnnotation = method.getAnnotation(MyAnnotation.class);
System.out.println("方法 " + method.getName() + " 的注解值: " + methodAnnotation.value());
}
}
}
}
输出:
类注解值: 类注解
方法 myMethod 的注解值: 方法注解
五、实际应用场景
-
框架配置
- Spring 的
@Component
、@Autowired
。 - JUnit 的
@Test
、@Before
。
- Spring 的
-
数据校验
- Hibernate Validator 的
@NotNull
、@Size
。
- Hibernate Validator 的
-
代码生成
- Lombok 的
@Getter
、@Builder
。
- Lombok 的
-
API 文档
- Swagger 的
@ApiOperation
、@ApiParam
。
- Swagger 的
六、面试常见问题
问题 1:注解和接口有什么区别?
- 注解:用于标记代码,本身不包含逻辑,需配合处理器使用。
- 接口:定义方法规范,由类实现具体逻辑。
问题 2:如何实现自定义注解的运行时处理?
- 通过反射 API(如
getAnnotation()
)读取注解信息,并根据注解内容执行逻辑。
问题 3:@Retention(RetentionPolicy.RUNTIME)
的作用是什么?
- 确保注解在运行时可通过反射读取,用于动态处理(如 Spring 的依赖注入)。
总结
Java 注解通过简洁的语法为代码添加元数据,广泛应用于框架配置、数据校验和代码生成。核心步骤包括:
- 定义注解:使用
@interface
和元注解。 - 使用注解:标注在目标代码元素上。
- 处理注解:通过 APT 或反射实现逻辑。
掌握注解机制,能够更好地理解现代 Java 框架(如 Spring)的设计思想,并编写更简洁、可维护的代码。