java元注解是定义自定义注解的规则制定者,包括@target(限定作用位置)、@retention(控制生命周期,runtime最常用)、@repeatable(支持同一位置重复使用)、@documented(纳入javadoc)和@inherited(类级注解可被子类继承)。

Java元注解是定义自定义注解的“规则制定者”,不掌握它们,就无法控制注解用在哪儿、保留到什么时候、是否参与文档生成或继承关系。它们不是可选技巧,而是构建任何注解驱动框架(如权限控制、参数校验、日志埋点)的底层基石。
@Target:精准限定注解能贴在哪儿
它决定注解的“作用域边界”。用错 ElementType,编译器直接报错,不会等到运行时才发现问题。
- 常见组合:@Target({METHOD, FIELD}) 表示既能标记方法也能标记字段;只写 @Target(METHOD) 就不能加在类上
- 易忽略的类型:TYPE_PARAMETER(泛型参数)、TYPE_USE(任意类型使用处,比如 List)从 Java 8 起支持,适合做细粒度类型约束
- 典型误用:想让注解同时用于方法和参数,却只写了 @Target(METHOD),结果 @MyAnno 出现在形参上时编译失败
@Retention:决定注解能活到哪一阶段
这是反射能否读取注解的关键开关。生命周期选错,注解就等于没写。
- RUNTIME:最常用,Spring 的 @Autowired、自定义拦截逻辑都依赖它,JVM 会保留到运行期,可通过 Class.getMethod().getAnnotation() 获取
- CLASS:保留在 .class 文件中但不加载进 JVM,适合字节码增强工具(如 ASM)处理,比如 Lombok 的 @Getter 编译期生成 getter 方法
- SOURCE:仅源码可见,编译完就丢弃,@Override 和 @SuppressWarnings 属于这一类,纯编译期检查
@Repeatable:解决“同一位置多个同名注解”的刚需
Java 8 之前,一个方法上只能有一个 @Valid 或一个 @Role,想配多个就得包一层容器注解。@Repeatable 让语法更自然。
- 必须配套容器注解:声明 @Repeatable(Permissions.class) 后,必须定义 public @interface Permissions { MyPermission[] value(); }
- 反射获取方式不同:不再用 getAnnotation(MyPermission.class),而要用 getAnnotationsByType(MyPermission.class)
- 适用场景明确:权限列表、多条件校验规则、多个切面配置等需要叠加语义的地方
@Documented 与 @Inherited:影响可见性与继承行为
这两个元注解不改变程序逻辑,但影响协作体验和设计意图传达。
- @Documented:加了它,Javadoc 生成时会把注解声明一起输出,团队成员看 API 文档就能知道哪些类/方法被打了特定标记
- @Inherited:仅对类级注解生效(ElementType.TYPE),子类自动获得父类的该注解;方法上的注解永远不会被继承,这点常被误解
- 注意限制:@Inherited 不传递给实现类(interface 实现不继承)、不跨模块生效,且仅限直接父类
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











