java注解本质是继承annotation接口的特殊元数据,不执行逻辑但可被编译器、工具或反射读取;与接口区别在于无参数方法、不可实例化;与类区别在于无字段方法体;元注解@target、@retention等控制作用位置与生命周期。

Java 注解(Annotation)是面试高频考点,答得好能体现你对语言机制、框架原理和代码设计的理解深度。关键不是背定义,而是讲清“为什么用”“怎么用”“底层怎么工作”“容易踩什么坑”。
注解本质是什么?和接口、类有什么区别?
注解是一种特殊的接口,编译后生成 .class 文件,但不能被实例化,也不继承 Object。它通过 @interface 声明,底层由 JVM 提供支持,属于元数据(metadata)——只描述代码,不参与运行逻辑。
- 与普通接口不同:注解方法不能有参数、不能有 throws、返回类型只能是基本类型/字符串/枚举/注解/以上类型的数组
- 与类不同:没有字段、方法体、构造器;不能 new,也不能被继承(除非用
@Inherited) - 注解本身可被其他注解修饰(如
@Target、@Retention),构成“元注解”体系
常见的元注解有哪些?分别控制什么?
元注解用于修饰其他注解,共 5 个标准注解,其中 4 个最常用:
-
@Target:指定注解能用在哪些位置(如
ElementType.METHOD、ElementType.TYPE)。不设则默认允许所有位置,但实际开发中必须明确限定 -
@Retention:决定注解存活时间。
RUNTIME表示保留到运行期(反射可用),CLASS仅保留在字节码中(AOP 编译期处理),SOURCE只在源码阶段(如@Override) - @Documented:标记该注解应被 Javadoc 工具记录,不影响运行,纯文档用途
- @Inherited:仅对类级别注解有效,表示子类会自动继承父类的该注解(注意:方法/字段上的注解不会被继承)
如何自定义注解并配合反射使用?
自定义注解常用于配置简化、校验、权限控制等场景。核心三步:定义 → 标注 → 解析。
- 定义时要配好
@Target和@Retention(RetentionPolicy.RUNTIME),否则反射读不到 - 属性写法类似接口方法,支持默认值(
default "xxx"),没默认值则使用时必须赋值 - 解析靠反射:
clazz.getAnnotation(MyAnno.class)或method.getAnnotation(MyAnno.class),再调用其方法获取值 - 注意:反射获取注解性能较低,生产环境建议缓存结果,或结合 APT 在编译期生成代码替代运行时反射
Spring 中的注解是怎么工作的?和 Java 原生注解关系是什么?
Spring 的 @Component、@Autowired、@Transactional 等都是基于 Java 原生注解实现的扩展,但它们本身不直接执行逻辑,而是由 Spring 容器在启动或代理时解析并触发行为。
-
@Component等是@Target({ElementType.TYPE})+@Retention(RetentionPolicy.RUNTIME)的普通注解,Spring 启动时扫描 classpath,用反射找出带这些注解的类,注册为 Bean -
@Autowired在依赖注入阶段由AutowiredAnnotationBeanPostProcessor处理,不是靠注解自身逻辑,而是 Spring 的后置处理器 -
@Transactional依赖 AOP,本质是动态代理 + 注解元数据提取,代理对象在方法调用前开启事务 - 所有这些都建立在 Java 注解机制之上,但功能由框架代码驱动,不是注解“自带能力”
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











