@target写错会导致编译失败,因java编译器严格校验注解使用位置,如误写为@target(elementtype.type)缺大括号、或用在非法位置均报错。

注解的 @Target 写错会导致编译失败
Java 编译器会严格校验注解是否用在了允许的位置上。比如你定义了一个只允许用在方法上的注解,却把它加在类上,javac 直接报错:Annotation is not applicable to this kind of declaration。
常见错误是把 @Target({ElementType.TYPE}) 误写成 @Target(ElementType.TYPE)(少了一层大括号),这会导致编译不通过——因为 @Target 要求的是 ElementType[] 数组,不是单个枚举值。
- 必须用花括号包住一个或多个
ElementType常量,如@Target({ElementType.METHOD, ElementType.FIELD}) - 如果只想限制单一位置,仍要写成数组形式:
@Target({ElementType.CONSTRUCTOR}),不能省略{} -
ElementType.TYPE_PARAMETER和ElementType.TYPE_USE是 Java 8 新增的,旧版本 JDK 下编译会失败
注解属性声明不加 default 值就只能显式赋值
自定义注解里每个方法声明都对应一个属性,但和普通接口不同:这些方法不能有参数、不能有 throws、返回类型只能是基本类型/字符串/Class/枚举/注解类型/以上类型的数组。
如果不写 default,使用时就必须显式提供该属性值,否则编译报错:Attribute value must be constant 或更常见的 Missing default value。
立即学习“Java免费学习笔记(深入)”;
- 推荐为所有非必需属性加上
default ""、default {}(空数组)、default -1等合理兜底值 - 数组类型的默认值必须写成
default {},不能写default []或留空 - 如果属性类型是另一个注解,
default只能设为default @MyOtherAnnotation(),不能为null
运行时读取注解要用 RetentionPolicy.RUNTIME
注解默认保留策略是 SOURCE,意味着它只在源码阶段存在,编译后就丢了。想在运行时通过反射拿到它,必须显式声明 @Retention(RetentionPolicy.RUNTIME)。
没加这个,哪怕 @Target 和属性都写对了,clazz.getAnnotation(MyAnno.class) 永远返回 null,而且没有任何警告。
-
@Retention(RetentionPolicy.CLASS)会被写入 class 文件,但 JVM 不加载;只有RUNTIME才能被反射读取 - Maven 编译时若用了
compiler-plugin的source/target设为 7 或更低,RUNTIME依然有效,但要注意某些 Android 环境会 strip 注解 - Spring 等框架依赖的就是
RUNTIME级注解;如果只做编译期检查(如 Lombok),SOURCE更轻量
反射获取注解属性时注意泛型擦除和数组边界
用 annotation.value() 这类调用读属性时,看似简单,但容易在两种情况出问题:一是属性是泛型集合(实际不可行,注解不支持泛型),二是属性是数组且长度为 0。
最常踩的坑是:以为 @MyAnno(names = {"a", "b"}) 的 names 属性可以直接当 List<string></string> 用,其实它就是 String[],需要手动转。
- 注解属性不支持泛型,
Class>[]是合法的,但List<string></string>会编译失败 - 空数组属性(如
default {})返回的是长度为 0 的数组,不是null,判空要用array.length == 0 - 如果属性类型是 Class,反射拿到的是运行时类对象,比如
value()返回String.class,不是字符串"java.lang.String"
注解本身不执行逻辑,它的威力完全取决于你怎么解析它。写得再规范,如果解析代码没处理好数组、没检查 isAnnotationPresent、或者忘了 @Retention,就等于白定义。










