Java注解到底存在多久?——源码、字节码与运行时

16 阅读1分钟

注解(Annotation)本质

注解就是给代码打的标签(元数据),编译后确实会被打包进 .class 文件,所以它可以被编译器、工具或运行时库读取。

三类生命周期

  1. 源码级(SOURCE)
    只在写代码时有效,编译完就消失,不会进 class 文件。

    • @Override:让编译器帮你检查是否真的覆写了父类方法,拼写错误直接报错。
    • @SuppressWarnings:告诉编译器「我知道这里有警告,闭嘴就好」。
  2. 字节码级(CLASS)
    会写进 class 文件,但 JVM 加载类时会丢弃,适合给静态分析工具(如 ProGuard)看。

  3. 运行时级(RUNTIME) ——最常用
    从类加载到程序结束一直留在 JVM 里,随时可以用反射读取。
    例如 @ResponseBody:当 Spring 检测到方法上有这个注解,就自动把返回值转成 JSON/XML 塞进 HTTP 响应体里,不用你手动写 response.getWriter().write()

自定义注解

@interface 关键字定义,本质是特殊的接口:

// 只能贴在类、接口、枚举上
@Target(ElementType.TYPE)  
public @interface MyController {
    String value();  // 注解的参数,使用时写成 @MyController("/user")
}

// 允许贴在方法或字段上
@Target({ElementType.METHOD, ElementType.FIELD})  
public @interface MyLog {
    String desc() default "默认日志";  // 可设默认值
}

@Target 的作用:限制你自定义的注解能贴在哪儿,防止写错位置。如果不写 @Target,默认可以贴任何位置。

快速记忆

  • 检查代码错误@Override(源码级)
  • 框架自动处理(如序列化、事务、权限)→ 自定义 RUNTIME 注解 + 反射
  • 写注解时 不知道能贴哪 → 加 @Target 约束一下