Java注解本质是继承Annotation接口的特殊接口,运行时通过动态代理实现,值由字节码中RuntimeVisibleAnnotations属性的Map提供;@Retention控制其生命周期:SOURCE仅存于源码,CLASS写入字节码但不加载,RUNTIME才可反射访问;注解本身不执行逻辑,需编译器、框架或工具链解析驱动。

Java 注解的底层本质是一个继承了 java.lang.annotation.Annotation 接口的特殊接口。
注解不是注释,也不是语法糖的简单包装
用 @interface 定义注解时,编译器会自动生成一个隐式继承 Annotation 的接口,并非普通类或抽象类。反编译后可清晰看到:
public interface MyAnnotation extends java.lang.annotation.Annotation- 所有属性方法(如
String value())都成为该接口的抽象方法 - 编译器在字节码中为其生成默认实现逻辑(比如
default值由代理对象内部 map 提供)
运行时拿到的注解对象其实是动态代理实例
调用 clazz.getAnnotation(MyAnnotation.class) 返回的不是一个真实类的实例,而是 JVM 通过 AnnotationInvocationHandler 创建的代理对象:
- 每次调用注解方法(如
anno.value()),实际触发invoke()方法 - 值从一个预加载的
Map中读取,该 Map 来源于字节码中的RuntimeVisibleAnnotations属性 - 这种设计既保证了不可变性,又避免了为每个注解创建具体类的开销
@Retention 决定了注解能否被反射读到
生命周期不是“存在与否”的模糊概念,而是由 JVM 类加载机制严格控制的:
立即学习“Java免费学习笔记(深入)”;
-
SOURCE:仅保留在源码,javac扫描后立即丢弃,字节码里没有 -
CLASS:写入 class 文件的attributes区,但类加载器不将其加载进运行时内存 -
RUNTIME:字节码中保留 + 类加载时解析并缓存到Class对象的annotations字段中,反射才能访问
注解本身不执行逻辑,必须靠外部解析器驱动
它只是数据载体,真正起作用的是配套机制:
- 编译期:注解处理器(
AbstractProcessor)扫描并生成新代码(如 Lombok) - 运行期:框架通过反射获取注解,再结合上下文做动作(如 Spring 解析
@Autowired做依赖注入) - 工具链:IDE、Javadoc、静态分析器等也各自读取对应生命周期的注解


















