首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Java注解详解

Java注解详解

原创
作者头像
艾伦耶格尔
发布2025-08-12 16:23:45
发布2025-08-12 16:23:45
5530
举报
文章被收录于专栏:Java高级Java高级

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<String> badCast() {
    return (List<String>) new ArrayList(); // 忽略类型转换警告
}

✅ 使用 @Deprecated 时建议添加 sinceforRemoval 属性,提高可维护性。


四、自定义注解:打造你的代码标记语言

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 在编译时自动生成 gettersettertoString 等方法。

自定义 APT 处理器步骤:
  1. 实现 javax.annotation.processing.Processor 接口
  2. 重写 process() 方法,扫描并处理目标注解
  3. 使用 Filer 生成新的 Java 文件
  4. 通过 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

参数校验


九、使用注解的最佳实践

  1. 命名清晰:注解名应表达明确语义,如 @Cacheable@Transactional
  2. 合理使用 @Retention:运行时注解慎用,避免性能开销。
  3. 避免过度使用:注解不是银弹,过多注解会降低代码可读性。
  4. 结合文档:使用 @Documented 提升 API 可维护性。
  5. 优先使用成熟框架注解:如 Spring、Jakarta EE 提供的标准注解。

结语

Java 注解是一种强大的元数据机制,它让代码具备了“自我描述”的能力。通过注解,我们可以实现:

  • 更安全的编译检查
  • 更简洁的配置方式
  • 更灵活的框架扩展
  • 更高效的开发体验

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、什么是注解?代码的“元数据标签”
    • 1.1 初识注解
  • 二、注解的三大用途
  • 三、Java 内置注解一览
    • 示例说明:
  • 四、自定义注解:打造你的代码标记语言
    • 4.1 定义一个自定义注解
    • 4.2 使用自定义注解
  • 五、元注解:控制注解的“规则”
    • 5.1 @Retention:注解的生命周期
    • 5.2 @Target:注解的适用位置
    • 5.3 其他常用元注解
  • 六、注解处理器:让注解“活”起来
    • 6.1 运行时处理:通过反射读取注解
    • 6.2 编译期处理:APT(Annotation Processing Tool)
      • 自定义 APT 处理器步骤:
  • 七、实战案例:自定义日志注解 + AOP 记录执行时间
    • 7.1 定义注解
    • 7.2 应用注解
    • 7.3 使用动态代理 + 反射实现日志功能
    • 7.4 测试
    • 输出结果:
  • 八、注解的典型应用场景
  • 九、使用注解的最佳实践
  • 结语
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档