Java注解本质是元数据标记,需配合处理器(编译期/运行时/构建期)才生效;自定义注解须含@Target、@Retention和属性定义;运行时获取需防空指针;Spring中如@Transactional在private方法无效,因代理机制无法拦截。

Java 注解是大厂面试高频考点,答得好能体现你对语言机制和框架底层的理解。关键不是背定义,而是讲清楚“为什么用”“怎么用”“容易踩什么坑”。
注解的本质是什么?别只说“元数据”
注解本身不带逻辑,它只是编译器或运行时可读的标记。真正起作用的是配套的处理器:编译期(如 @Override 由编译器检查)、运行时(如 Spring 的 @Autowired 由反射+BeanFactory处理)、或者构建期(如 Lombok 的注解由注解处理器生成代码)。面试时点明“注解 + 处理器 = 完整能力”,比单说“它是元数据”更有深度。
自定义注解的三要素必须说全
写一个可用的自定义注解,缺一不可:
- @Target:声明能用在哪儿(类、方法、参数等),比如 @Target(ElementType.METHOD)
- @Retention:声明生命周期(SOURCE/CLASS/RUNTIME),多数框架注解必须是 RetentionPolicy.RUNTIME
- 属性定义:用方法形式声明,返回类型只能是基本类型、String、Class、枚举、其他注解或以上类型的数组
运行时获取注解,反射不是万能钥匙
用 getAnnotation() 或 getDeclaredAnnotations() 获取注解后,别直接调方法——注意空指针。常见写法:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
if (method.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation ann = method.getAnnotation(MyAnnotation.class);
String value = ann.value(); // 安全取值
}
还要提醒:泛型擦除后,无法通过反射拿到泛型上的注解;private 方法默认不被父类反射获取到,需配合 getDeclaredMethod() + setAccessible(true)(但注意 SecurityManager 限制)。
Spring 中的注解,重点讲清“谁在解析”
面试官爱问 @Transactional 为什么加在 private 方法上无效?答案核心是:Spring AOP 代理模式决定的。JDK 动态代理只代理接口方法,CGLIB 代理子类方法,但都依赖“外部调用触发代理逻辑”。private 方法绕过代理链,注解自然不生效。同理,@Async、@Cacheable 都有类似限制。这不是注解的问题,是代理机制的边界。
搞懂这些,面试时就能从语法层穿透到机制层,稳拿高分。

















