Java注解的作用是啥

🔹 注解到底是什么,先给它卸个妆

注解本质上就是个不会动的标签。你贴在类上、方法上、字段上,它自己啥也不干,就是个标记。真正干活的,是后面读这个标签的注解处理器(编译期的插件,或者运行时的反射代码)。

🔹 按作用分,我自己习惯归为三档

级别 谁在干活 典型例子 我对它的感觉
🛡️ 源码级 编译器 @Override, @Deprecated, @SuppressWarnings 像帮你检查作业的助教,错一点就喊你
⚙️ 编译时 注解处理器 (APT) Lombok 的 @Data, MapStruct 的 @Mapping 在编译期偷偷帮你写代码,运行时看不见
🧠 运行时 反射 Spring 的 @Autowired, JUnit 的 @Test 框架的灵魂,靠这个才不用写一堆 XML

🔹 面试可以这样展开说

✅ 编译期做检查 @Override 帮你检查是不是真的重写了父类方法,写错一个字母编译器就直接甩错误——这比代码评审可靠一百倍。

✅ 编译期生成代码 我最喜欢的例子是 Lombok。你写一个 @Data,反编译 class 文件之后 getter/setter/equals/hashCode/toString 全给你生成了。注解本身不做这些,是 Lombok 的注解处理器在编译期间操作了抽象语法树(AST),把代码塞进去了。

✅ 运行时框架整合 Spring 扫描到 @Service,就把类注册成 Bean;看到 @Transactional,就生成一个 AOP 代理帮你管理事务。底层都是 class.getAnnotation()method.isAnnotationPresent(),对着反射一顿操作。注解在这里就是框架和程序员之间的“暗号”。

🔹 自定义注解怎么写,可以背个极简模板

@Retention(RetentionPolicy.RUNTIME)  // 活到运行时,反射能读到
@Target(ElementType.METHOD)          // 只能贴在方法上
public @interface Loggable {
    String value() default "";
}

然后写个切面或拦截器,一看到有这个注解的方法就自动打日志。这一套下来,注解的“标记+处理”模式就闭环了。

🔹 面试容易漏掉的元注解

光说怎么用不行,还得知道元注解(注解的注解):

  • @Retention 控制生命周期(SOURCE/CLASS/RUNTIME)

  • @Target 控制贴哪儿

  • @Inherited 子类能自动继承

  • @Documented 进 javadoc

  • @Repeatable 能反复贴(Java 8 以后)

追问如果问你“注解里的值为什么只能放常量”,那是因为注解的属性在编译时就得确定,写进 class 文件的结构里,没法存动态对象。