@Target仅声明注解使用规则,由javac在AST构建阶段静态校验位置合法性,位置不符立即编译报错;value必须为ElementType[]数组形式;未声明@Target则默认允许除TYPE_PARAMETER外所有位置;TYPE_USE需配套工具或API才生效。

@Target 本身不执行检查,它只是向编译器提供一条“使用规则”。真正执行约束的,是 javac 在解析源码时对注解出现位置的静态校验——只要发现注解被用在了 @Target 不允许的位置,立刻报错,不生成 class 文件。
编译期即时拦截非法标注
javac 在 AST(抽象语法树)构建阶段就识别注解及其元信息。一旦读取到某个自定义注解带有 @Target({ElementType.METHOD}),而实际出现在字段声明上,就会触发 JLS 9.7.4 规定的合法性检查,抛出类似这样的错误:
- error: Annotation is not applicable to this kind of declaration
- 不会等到运行时,也不依赖任何框架或插件
- 哪怕注解类本身逻辑完整、@Retention 设置正确,位置错就直接失败
数组写法是硬性语法要求
@Target 的 value 是 ElementType[] 类型,所以必须用花括号包裹:
- ✅ 正确:
@Target({ElementType.FIELD, ElementType.PARAMETER}) - ❌ 错误:
@Target(ElementType.FIELD)—— 编译失败,类型不匹配 - ❌ 错误:
@Target({})—— 表示禁止用于任何位置,极少使用
空 @Target 等价于“全开放”
如果自定义注解没写 @Target,默认允许出现在除 TYPE_PARAMETER 外的所有声明位置(JLS 规定)。这看似灵活,实则削弱约束力:
- 比如一个专用于参数校验的 @NotNull,若没设 @Target,就可能被误加在类上,语义混乱
- IDE 和框架(如 Hibernate Validator)会依据 @Target 决定是否启用对应处理逻辑
- 不设 @Target = 放弃第一道结构防线
TYPE_USE 的特殊性:需要配套 API 才可见
@Target(ElementType.TYPE_USE) 允许标注泛型、类型转换等位置,但 javac 不会仅凭它做额外校验:
- 例如
List<@NonNull String>合法,但编译器默认不检查 null 安全性 - 要真正生效,需搭配 Checker Framework 或启用 -processor 参数
- 反射读取时必须调用
getAnnotatedType(),getGenericType()返回的 Type 对象不含这些注解

















