@Target 注解通过限定注解适用位置实现编译期静态检查,需配合 @Retention 指定保留策略,并依赖特定 API(如 getAnnotatedType)才能读取 TYPE_USE 注解,单独使用无法触发实际校验。

@Target 注解本身不执行类型检查,但它为编译器增强代码健壮性提供了关键前提——通过精确限定注解的适用位置,使编译器能在编译期发现非法使用,从而提前拦截错误。
明确作用范围,避免误用
当你定义一个注解并指定 @Target({ElementType.METHOD}),编译器就会强制校验:该注解只能出现在方法声明上。一旦加在字段、类或参数上,javac 直接报错:Annotation is not applicable to this kind of declaration。这种静态约束无需运行时开销,却能有效防止配置错位、语义混淆等低级但高频的问题。
- 少写大括号(如 @Target(ElementType.METHOD))会导致编译失败,因为 @Target 要求 ElementType[] 数组类型
- 若同时支持多个位置,必须显式列出,例如 @Target({ElementType.FIELD, ElementType.PARAMETER})
- Java 8 新增的 TYPE_USE 和 TYPE_PARAMETER 在 JDK 7 及以下版本中不可用,编译会直接拒绝
配合编译器插件实现深度检查
@Target(ElementType.TYPE_USE) 是实现泛型级类型约束的基础,但它本身不触发检查。真正起作用的是配套工具链:
- Checker Framework 等插件利用 TYPE_USE 信息,在编译期对
List<@NonNull String>中的@NonNull做空值流分析 - IDE(如 IntelliJ 或 Eclipse)根据 @Target 提示可用位置,自动补全并高亮非法标注
- Lombok、MapStruct 等代码生成工具依赖 @Target 定位目标元素,确保生成逻辑只作用于预期结构
与 @Retention 协同决定检查时机
健壮性不仅取决于“能标在哪”,还取决于“标了有没有效”:
- @Retention(RetentionPolicy.SOURCE):仅源码可见,适合语法提示类注解(如 @Override),编译器可即时校验但不保留
- @Retention(RetentionPolicy.CLASS):写入 class 文件,供字节码分析工具(如 PMD、FindBugs)扫描
- @Retention(RetentionPolicy.RUNTIME):反射可读,框架可在运行时做动态校验(如 Spring 的 @Validated 解析 @NotNull)
没有 @Retention 配合,哪怕 @Target 写得再精准,也无法支撑任何实际检查逻辑。
反射读取需对应 API 才能提取 TYPE_USE 信息
泛型上的注解(如 Map<@NotBlank String, @Positive Integer>)不会出现在普通反射接口中:
-
field.getGenericType()返回的是原始 Type,不含注解 - 必须调用
field.getAnnotatedType()获取 AnnotatedType 实例 - 再逐层展开 AnnotatedParameterizedType、AnnotatedTypeVariable 等,才能定位到泛型参数上的 TYPE_USE 注解
这意味着运行时校验逻辑必须主动适配这套 API,否则 TYPE_USE 标注形同虚设。

















