@target的作用是限定注解可声明的语法位置,必须用elementtype[]数组形式指定,如@target({elementtype.method}),缺括号或遗漏type_parameter、type_use等关键类型将导致编译失败或运行时不可见。

@Target 的作用很实在:它不是用来“限制”你写代码的自由,而是让编译器清楚知道——这个注解只允许出现在哪些语法位置上。写错地方,javac 直接报错,连 class 文件都不会生成。真正关键的是用 ElementType[] 组合多个值,既精准覆盖业务需要的位置,又避免意外开放不该支持的地方。
必须用数组写法,单个值也不能省括号
Java 要求 @Target 的 value 必须是 ElementType[] 类型。哪怕只限定一个位置,也得用大括号包住:
- ✅ 正确:@Target({ElementType.METHOD})
- ✅ 正确:@Target({ElementType.TYPE, ElementType.METHOD})
- ❌ 错误:@Target(ElementType.METHOD)(缺少数组括号,编译失败)
- ❌ 错误:@Target({ElementType.TYPE_USE}) 却想标在类声明上(TYPE_USE 不包含 TYPE,必须显式加上)
按框架场景选组合,不是随便堆砌
不同用途的注解,对应不同的 ElementType 组合策略。重点看后续怎么被读取和使用:
- 方法 + 字段:适合日志、审计类注解,比如 @AuditLog,既要拦截方法执行,也要标记敏感字段
- 类 + 方法:适合 AOP 拦截场景,如 @Transactional,允许加在 Service 类整体或具体方法上
- 参数 + 方法:适合参数校验框架,如自定义 @ValidatedParam,需同时支持形参和整个方法入口
- TYPE + TYPE_PARAMETER + TYPE_USE:面向泛型增强的注解,例如类型安全检查,三者缺一不可
别漏掉 Java 8 新增的两个关键类型
TYPE_PARAMETER 和 TYPE_USE 常被忽略,它们不走传统反射路径,也不被默认包含:
-
TYPE_PARAMETER 出现在泛型声明处,如 class Box,反射要用
Class.getTypeParameters() -
TYPE_USE 出现在任意类型使用处,如 List 或 new @Immutable ArrayList(),反射需调用
getAnnotatedParameterTypes()等带 Annotated 前缀的方法 - 如果没在 @Target 中显式列出,这些位置即使写了注解,字节码里也不会保留
@Target 和 @Retention 是两件事,得一起配
一个管“能写在哪”,一个管“能活到哪”:
- @Target({ElementType.METHOD}) 表示只能标在方法上,编译期强制拦截
- @Retention(RetentionPolicy.RUNTIME) 表示注解信息保留在运行时,反射才能拿到
- 只设 @Target 不设 @Retention:注解编译通过但运行时读不到
- 只设 @Retention 不设 @Target:注解定义本身就不合法(截至 2026 年 6 月)











