注解是贴在代码上的标签,本身不执行逻辑;其作用取决于@retention(生命周期)和@target(作用位置),且必须配合编译器、框架或反射主动读取才能生效。

攻克Java注解原理,关键不在死记元注解名称,而在于理清“谁在什么时候看到它、又拿它做什么”。只要抓住生命周期和处理主体这两条主线,面试再难的注解题都能拆解清楚。
注解不是代码,是贴在代码上的标签
很多人一上来就以为注解会自动执行逻辑,这是最大误区。@Transactional 不会自己开启事务,@Override 也不会自动重写方法——它们只是标签。真正干活的是:
- 编译器(如 javac):看到 @Override 就检查是否真重写了父类方法
- 框架容器(如 Spring):启动时扫描 @Component,把类注册成 Bean
- 代理或切面(如 AOP):运行时拦截标了 @Log 的方法,自动打印日志
- 你写的反射工具类:调用 method.getAnnotation(MyAnno.class) 拿到信息后做业务判断
@Retention 决定它能活到哪一步
这个元注解直接决定注解有没有机会被“看见”:
- SOURCE:只在.java文件里存在,编译完就消失。@Override 就是它——编译器用完即扔,反射永远读不到
- CLASS:写进.class文件,但 JVM 加载时不加载进内存。默认值,多数自定义注解没显式声明就走这条路,反射也读不到
- RUNTIME:唯一能让反射读取的级别。Spring 的 @Autowired、自定义校验注解必须设为它
面试常考陷阱:@Retention(RetentionPolicy.CLASS) 的注解,能不能用 Class.getAnnotation() 获取?不能。必须是 RUNTIME。
@Target 控制它能贴在哪儿
不是所有地方都能打标签,@Target 就是“使用说明书”:
- 想只让注解放在方法上?@Target(ElementType.METHOD)
- 想同时支持类和字段?@Target({ElementType.TYPE, ElementType.FIELD})
- 贴错位置会直接编译失败,比如给局部变量加了只允许 TYPE 的注解
自定义注解生效的两个必要条件
光写个 @interface 远远不够,缺一不可:
- 保留策略必须是 RUNTIME:否则反射读不到,后续一切归零
- 必须有代码主动读取它:要么自己写反射遍历,要么交给 Spring 的 @Bean + AOP,或者用 Processor 在编译期生成新类
常见失效原因:忘了加 @Retention(RetentionPolicy.RUNTIME),或者写了注解却没写任何解析逻辑——就像冰箱门上贴了“买牛奶”,但家里没人看那张纸。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











