java注解是元数据容器,不执行逻辑,分source、class、runtime三类生命周期;自定义运行时注解需完备四大要素:@target、@retention(runtime)、public @interface、无参方法属性;反射读取遵循获取元素→检查存在→取值三步;结合aop实现日志/权限等需定义注解+切面拦截+反射读取。

Java 注解(Annotation)是面试和实际开发中的高频考点,核心不在于背语法,而在于理解“谁在用、何时用、怎么用、为什么这么设计”。下面按真实考察逻辑组织内容,直击重点。
注解的本质:不是代码,是元数据容器
注解本身不执行任何逻辑,它只是给编译器、JVM 或第三方框架(如 Spring、JUnit)提供结构化信息。关键要分清三类生命周期:
- @Retention(RetentionPolicy.SOURCE):仅在源码阶段有效(如 @Override),编译后丢弃
- @Retention(RetentionPolicy.CLASS):编译进 .class 文件但运行期不可见(较少用)
- @Retention(RetentionPolicy.RUNTIME):运行时可通过反射读取(如 @RequestMapping、自定义校验注解)——这是最常考、最实用的一类
自定义注解的四大要素必须写全
手写一个可用的运行时注解,缺一不可:
- @Target:声明能标注在哪(METHOD、FIELD、TYPE 等),不写默认允许所有位置,但面试常考限制合理性
- @Retention(RetentionPolicy.RUNTIME):没它,反射 getAnnotations() 拿不到
- public @interface Xxx:必须是 public + interface 关键字
- 方法声明:用无参方法定义属性(不是字段!),支持 default 值,如 String value() default "";
常见错误:漏 @Target、用 private 或 void 方法、把注解当普通类写构造器。
运行时读取注解的反射套路要熟练
核心就是三步:获取元素 → 检查是否有该注解 → 取值。以方法上注解为例:
Method method = targetClass.getMethod("xxx");<br>if (method.isAnnotationPresent(MyLog.class)) {<br> MyLog anno = method.getAnnotation(MyLog.class);<br> System.out.println(anno.value()); // 调用注解属性方法<br>}
注意:
• getAnnotation() 返回 null 表示没该注解,不是异常
• isAnnotationPresent() 比判空更高效(JVM 优化)
• 注解属性调用本质是动态代理,不能直接 new 或设值
和 AOP、Spring 的结合是实战重点
面试最爱问:“怎么用注解实现日志/权限/事务?”答案不是硬背 Spring 源码,而是说清链路:
- 定义注解(@Log、@RequireRole)并标记 @Retention(RUNTIME) 和 @Target(METHOD)
- 写一个切面(@Aspect),用 @Around("@annotation(com.xxx.Log)")拦截
- 在通知方法里通过 JoinPoint 获取目标方法 → 反射读注解 → 执行对应逻辑(记录日志、校验角色)
关键点:Spring 不“解析”注解,而是靠 AOP 拦截 + 反射读取,框架只是帮你省了手动注册切点的麻烦。
易混淆点辨析(高频陷阱)
• @Override 是编译期检查,不是运行时注解
• @SuppressWarnings("unchecked") 作用域是紧邻的代码块或声明,不是全局生效
• 注解不能继承,但可以用 @Inherited 让子类继承父类的类级注解(仅限 CLASS 类型,且只对类有效)
• 元注解(@Target/@Retention 等)本身也是注解,它们标注的是其他注解
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











