面试知识库
进阶

Java注解原理#

一句话答案#

注解是元数据标记,通过 @Retention 控制保留策略,运行时注解靠反射读取,编译时注解靠 APT 处理。

核心要点

注解的本质:

  • 注解是元数据标记(@interface 定义),本身不包含业务逻辑
  • 逻辑全靠处理器实现(反射处理 / APT 编译时处理)

四个核心元注解:

元注解作用常用值
@Retention注解保留策略SOURCE(编译丢弃)/ CLASS(字节码保留)/ RUNTIME(运行时可反射读取)
@Target注解适用目标TYPE / METHOD / FIELD / PARAMETER 等
@Documented是否写入 Javadoc
@Inherited子类是否继承父类的注解

两种处理方式:

运行时注解(RUNTIME):
  → 通过反射 getAnnotation() 读取注解信息
  → Spring 的 BeanPostProcessor 扫描 @Autowired/@Transactional 就是这种方式

编译时注解(SOURCE/CLASS):
  → 通过 APT(Annotation Processing Tool)在编译阶段生成代码
  → Lombok 的 @Data 就是编译时生成 getter/setter/toString
plaintext

自定义注解三步走:

  1. @interface 定义注解,加上 @Retention@Target
  2. 编写处理逻辑(反射读取或 APT 处理器)
  3. 在目标位置使用注解
面试回答(2分钟版)

Java注解本质上是一种元数据标记,它本身不包含任何业务逻辑,逻辑全靠处理器实现。注解通过@interface定义,用元注解控制行为:@Retention决定注解的生命周期——SOURCE级别编译后丢弃如@Override、CLASS级别保留到字节码但运行时不可见、RUNTIME级别运行时可通过反射读取,Spring的大部分注解都是RUNTIME级别;@Target指定注解能标注在哪里,比如方法、类或字段。运行时注解的处理靠反射:通过getAnnotation方法读取注解信息然后执行相应逻辑,Spring的BeanPostProcessor就是这样扫描@Autowired、@Transactional等注解并做处理的。编译时注解靠APT注解处理器在编译阶段生成代码,比如Lombok的@Data就是在编译时生成getter/setter/toString。自定义注解三步走:用@interface定义注解并加上元注解、编写处理逻辑(反射或APT)、在目标位置使用。关键要记住注解只是标记,真正干活的是处理器。

追问与易错

追问方向:

  • “@Retention 三种策略的区别?”→ SOURCE 编译后丢弃(如 @Override);CLASS 保留到字节码但运行时不可见(默认值);RUNTIME 运行时通过反射可读取(Spring 注解均为此级别)
  • “Spring 的注解是怎么生效的?”→ BeanPostProcessor 在 Bean 初始化前后通过反射扫描注解并执行相应逻辑,如 AutowiredAnnotationBeanPostProcessor 处理 @Autowired 注入
  • “自定义注解怎么做?”→ 用 @interface 定义注解、加 @Retention 和 @Target 元注解指定生命周期和作用目标、编写处理器(反射读取或 APT 编译时处理)

易错点:

  • ❌ “注解本身有逻辑”——注解只是标记,逻辑在处理器(反射/APT)中
  • ❌ 混淆编译时注解和运行时注解的处理方式