注解是提供元数据的接口形式,不执行逻辑,由编译器、工具或运行时通过反射等机制读取处理,其生命周期由@Retention指定,参数类型受限以确保可序列化和安全传递。

Java注解(Annotation)本质上是一种**元数据(metadata)**,它不是程序逻辑的一部分,也不直接影响代码的运行行为,而是为编译器、工具或运行时提供**结构化信息**,供其读取、解析并作出相应处理。
注解是接口的特殊形式
每个注解在底层都对应一个继承自 java.lang.annotation.Annotation 的隐式接口。当你写:
@Override
public void run() { ... }
这里的 @Override 实际上是一个接口定义(由 JDK 提供),JVM 在加载类时会生成该注解的代理实例。你可以用反射获取它,但不能 new 它,也不能直接实现它——编译器会自动完成接口实现与实例构建。
注解本身不执行任何逻辑
注解就像“贴在代码上的标签”,它不做事情,真正做事的是:
立即学习“Java免费学习笔记(深入)”;
- 编译器(如 @Override 在编译期检查方法签名)
- 注解处理器(APT,如 ButterKnife、Lombok 在编译期生成额外代码)
- 运行时反射(如 Spring 用 @Autowired 在启动时注入依赖)
没有配套的“消费者”,注解就只是静态信息,不会触发任何动作。
生命周期由 @Retention 决定
注解能活多久,取决于它的保留策略:
- RetentionPolicy.SOURCE:仅在源码中存在(如 @Override),编译后丢弃
- RetentionPolicy.CLASS:存入 .class 文件,但 JVM 不加载进内存(APT 常用)
- RetentionPolicy.RUNTIME:完整保留在运行时,可通过反射读取(如 @RequestMapping)
选错保留策略会导致反射拿不到注解,或者编译器无法做校验——这是常见踩坑点。
注解可以有参数,但限制严格
注解成员只能是以下类型:
- 基本类型(int、boolean 等)
- String、Class、枚举、其他注解
- 以上类型的数组(如 String[] value() default {})
不能是任意对象、泛型、lambda 或 null,默认值必须是编译期常量。这保证了注解信息可序列化、可跨平台安全传递。
基本上就这些。理解注解的“被动性”和“契约性”,才能用好它——它不是魔法,而是一套约定清晰的元数据通信机制。











