@Retention(RetentionPolicy.RUNTIME)几乎是必须的,因多数场景需运行时反射读取注解;@Target需精确指定适用位置,否则编译失败;注解属性仅支持基本类型、String、Class、枚举、其他注解及一维数组。

注解本身不执行逻辑,但它是让框架、工具或运行时能“读懂”你意图的关键桥梁——用错位置、忽略保留策略或类型不匹配,@Retention 和 @Target 配置不对,注解就等于没写。
为什么 @Retention(RetentionPolicy.RUNTIME) 几乎是必须的
多数实用场景(如 Spring 的 @Autowired、JUnit 的 @Test)都需要在运行时通过反射读取注解。如果只写 @Retention(RetentionPolicy.CLASS) 或默认的 SOURCE,编译后注解就消失了,Class.getAnnotations() 会返回空数组。
-
@Retention(RetentionPolicy.SOURCE):仅保留在源码中,javac 处理完即丢弃(适合@Override这类编译检查) -
@Retention(RetentionPolicy.CLASS):存入 .class 文件,但 JVM 不加载进内存,反射不可见 -
@Retention(RetentionPolicy.RUNTIME):写进字节码且可被反射读取,90% 自定义注解需要它
@Target 写错会导致编译失败
声明注解时若未指定 @Target,它默认允许加在任意位置;但一旦写了,就必须覆盖所有你真会用到的地方,否则编译器直接报错:Annotation is not applicable to this kind of declaration。
- 想标注字段和方法?得同时写
@Target({ElementType.FIELD, ElementType.METHOD}) - 只写
@Target(ElementType.METHOD)却往字段上加,IDE 和 javac 都会拒绝 - 常见误用:
ElementType.TYPE_PARAMETER是泛型形参(如class Box<t></t>中的T),不是泛型实参(如Box<string></string>),别混淆
自定义注解里别直接放复杂对象
注解属性只支持有限类型:基本类型、String、Class、枚举、其他注解,以及它们的一维数组。不能写 List、Map 或自定义 POJO。
- 错误示例:
public List<string> values() default new ArrayList();</string>→ 编译失败 - 正确替代:
public String[] values() default {};,调用方用Arrays.asList(annotation.values())转 - 如果真要传递结构化数据,考虑用 JSON 字符串 + 手动解析,但需自行处理异常和兼容性
最常被跳过的一步是:忘了在使用注解的类/方法上加 @Retention(RUNTIME),结果反射死活读不到——它不像 @Override 那样有编译器内置逻辑,纯靠配置生效。

















