要真正用好@target(elementtype.type_use),关键在于理解其标注位置、配套读取方式(annotatedtype体系)和校验机制(需checker framework等工具链支持),它本身不执行检查。

要真正用好 @Target(ElementType.TYPE_USE),关键不是“加上就行”,而是理解它覆盖的位置、配套的读取方式和实际校验机制。它本身不执行检查,只开放标注入口——后续靠编译器插件或反射解析来兑现语义。
TYPE_USE 能标在哪些地方?先看清边界
只要代码里出现“类型字面量”的位置,基本都算 TYPE_USE 的管辖范围。常见但容易忽略的包括:
- 泛型实参:
List、Map - 通配符边界:
List extends @Immutable Object>、Set super @Validated User> - 泛型方法形参约束:
<t extends object> void process(T t)</t> - 类型转换表达式:
(@NonNull String) obj - 数组元素类型:
@NonNull String[](注意不是String[] @NonNull) -
new表达式中的类型:new @Immutable ArrayList() -
implements/throws/extends子句中的类型:class A implements @Experimental Service
定义注解时必须显式声明 TYPE_USE
仅写 @Target(ElementType.TYPE_USE) 不够,语法上必须是数组形式;同时建议叠加常用位置,提升实用性:
✅ 正确写法:@Target({ElementType.TYPE_USE, ElementType.FIELD, ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)public @interface NonNull { }
❌ 常见错误:@Target(ElementType.TYPE_USE) —— 缺少大括号,编译直接失败@Target({ElementType.TYPE}) —— 不支持泛型内标注,List 会报错
运行时怎么读到泛型里的 TYPE_USE 注解?
不能用传统反射 API,必须切换到 AnnotatedType 体系:
- 字段:用
field.getAnnotatedType()替代field.getGenericType() - 方法参数:用
method.getAnnotatedParameterTypes() - 方法返回值:用
method.getAnnotatedReturnType() - 解析泛型实参示例:
若字段声明为List list;,需这样提取:AnnotatedType[] args = ((AnnotatedParameterizedType) annotatedType).getAnnotatedActualTypeArguments();
然后检查args[0].getAnnotations()获取@Deprecated
真正生效还得靠配套工具链
声明 TYPE_USE 只是第一步。是否触发检查、如何报错,取决于外部支持:
-
编译期校验:需集成 Checker Framework 等插件,配合
@NonNull等注解实现空安全检查 -
运行时逻辑:框架如 Hibernate Validator 5+ 支持
@NotBlank标在泛型参数上,但需调用Validator#validate并传入ConstraintViolation的完整上下文 - IDE 支持:IntelliJ 和 Eclipse 需启用相应检查插件,否则不会高亮或提示泛型级违规











