第41章 Java注解(Annotations)
面包屑导航 章节标题 学习目标
学习目标
- 理解Java注解的概念和作用机制
- 掌握内置注解的使用方法和应用场景
- 学会创建和使用自定义注解
- 了解元注解的类型和配置方式
- 掌握通过反射读取和处理注解信息
- 学会创建简单的注解处理器
- 了解注解在实际开发中的最佳实践
注解概述
什么是Java注解
注解(Annotation)是Java 5引入的重要特性,它提供了一种为代码添加元数据的方式。注解本身不会改变程序的执行逻辑,但可以被编译器、开发工具或运行时环境读取和处理。
注解的作用
- 编译时检查:如@Override检查方法重写是否正确
- 代码生成:如Lombok的@Getter、@Setter自动生成代码
- 运行时处理:如Spring的@Autowired、@Component进行依赖注入
- 文档生成:如@Deprecated标记废弃的API
- 配置管理:如@Value读取配置文件中的值
内置注解
Java内置注解
@Override
标记重写父类的方法,编译器会检查方法签名是否正确。
@Deprecated
标记已废弃的类、方法或字段,编译器会产生警告。
@SuppressWarnings
抑制编译器警告信息,如未检查的类型转换警告。
@SafeVarargs
标记安全的可变参数方法,抑制堆污染警告。
@FunctionalInterface
标记函数式接口,确保接口只有一个抽象方法。
public class AnnotationBasics {
// 标记已废弃的方法
@Deprecated
public void oldMethod() {
System.out.println("已废弃的方法");
}
// 标记重写的方法
@Override
public String toString() {
return "AnnotationBasics{}";
}
// 抑制编译器警告
@SuppressWarnings("unchecked")
public void methodWithWarnings() {
java.util.List list = new java.util.ArrayList();
list.add("Hello");
}
// 函数式接口
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}
}
💻 查看完整代码 - 在线IDE体验 自定义注解
自定义注解
创建自定义注解
自定义注解使用@interface关键字定义,可以包含属性和默认值。
import java.lang.annotation.*;
// 作者信息注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Author {
String name() default "Unknown";
String email() default "";
String date() default "";
}
// 版本信息注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Version {
double value() default 1.0;
String description() default "";
}
// 测试方法注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
String description() default "";
boolean enabled() default true;
int timeout() default 0;
}
元注解详解
@Retention
指定注解的生命周期:SOURCE、CLASS、RUNTIME
@Target
指定注解可以应用的目标:TYPE、FIELD、METHOD等
@Documented
标记注解是否包含在Javadoc中
@Inherited
标记注解是否可以被子类继承
反射读取注解
反射读取注解
通过Java反射API可以在运行时读取和处理注解信息。
public class CustomAnnotations {
@Author(name = "张三", email = "[email protected]")
@Version(value = 1.0, description = "初始版本")
@Test(description = "测试计算功能", enabled = true)
public int calculate(int a, int b) {
return a + b;
}
public static void readAnnotations() throws Exception {
Method method = CustomAnnotations.class.getMethod("calculate", int.class, int.class);
// 读取Author注解
if (method.isAnnotationPresent(Author.class)) {
Author author = method.getAnnotation(Author.class);
System.out.println("作者: " + author.name());
System.out.println("邮箱: " + author.email());
}
// 读取Version注解
if (method.isAnnotationPresent(Version.class)) {
Version version = method.getAnnotation(Version.class);
System.out.println("版本: " + version.value());
System.out.println("描述: " + version.description());
}
// 读取Test注解
if (method.isAnnotationPresent(Test.class)) {
Test test = method.getAnnotation(Test.class);
System.out.println("测试描述: " + test.description());
System.out.println("是否启用: " + test.enabled());
}
}
}
注解处理器
注解处理器
注解处理器可以在编译时或运行时处理注解,实现各种功能如验证、日志、缓存等。
// 验证注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Validate {
String message() default "验证失败";
boolean required() default false;
}
// 用户实体类
public class User {
@Validate(required = true, message = "用户名不能为空")
private String username;
public User(String username) {
this.username = username;
}
}
// 验证处理器
public class ValidationProcessor {
public static List validate(Object obj) {
List errors = new ArrayList<>();
try {
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Validate.class)) {
field.setAccessible(true);
Validate validate = field.getAnnotation(Validate.class);
Object value = field.get(obj);
if (validate.required() &&
(value == null || value.toString().trim().isEmpty())) {
errors.add(validate.message());
}
}
}
} catch (Exception e) {
errors.add("验证错误: " + e.getMessage());
}
return errors;
}
}
注解最佳实践
注解最佳实践
注解设计和使用原则
好的实践
- 明确注解的目的和作用域
- 提供合理的默认值
- 使用有意义的名称
- 添加完整的文档说明
- 考虑性能影响
应该避免
- 过度使用注解
- 注解参数过多
- 忽略性能开销
- 缺乏文档说明
- 不合理的生命周期设置
性能提示:反射操作有一定的性能开销,在高频调用的场景中应该考虑缓存注解信息,避免重复的反射操作。
实际应用场景
实际应用场景
数据验证
使用注解标记字段验证规则,如@NotNull、@Size、@Email等
依赖注入
Spring框架的@Autowired、@Component、@Service等
ORM映射
JPA的@Entity、@Table、@Column等数据库映射注解
Web开发
Spring MVC的@Controller、@RequestMapping、@ResponseBody等
序列化
Jackson的@JsonProperty、@JsonIgnore等JSON序列化注解
单元测试
JUnit的@Test、@Before、@After等测试注解
章节导航