Java 注解本质上是一种“给代码添加元信息(metadata)”的机制。
但注解真正的价值来自:
反射能够读取注解内容并执行相应逻辑。
也就是说:
注解 = 贴在代码上的信息
反射 = 把这些信息读出来并使用它的工具
Spring、MyBatis、JUnit 全靠它们运作。
一、注解是什么?
注解(Annotation)是写在类、方法、字段上的一种“说明信息”。
作用包括:
-
标记(如
@Override) -
编译期检查(如
@Deprecated) -
运行时配置(如 Spring 的
@Autowired、@Controller)
注解本身 不做任何逻辑,是反射让它“活”起来的。
二、自定义注解(Core)
自定义注解格式:
public @interface MyAnnotation {
String value();
int age() default 18;
}
特点:
-
方法名 = 注解的属性名
-
返回值类型 = 属性类型
-
可设默认值
-
无参数构造、不允许继承类
三、元注解:注解的注解
Java 提供 4 个常用元注解:
⚫ @Target:注解能用在哪(类?方法?字段?)
⚫ @Retention:注解何时生效(源码?编译期?运行时?)
⚫ @Documented:是否加入 Javadoc
⚫ @Inherited:能否被子类继承
最关键的是:
✔ 要让反射读取注解,必须使用
@Retention(RetentionPolicy.RUNTIME)
四、给类/方法/字段添加注解
例子:
@MyAnnotation(value = "hello", age = 22)
public class Person {
@MyAnnotation("field test")
private String name;
@MyAnnotation(value = "method test", age = 99)
public void test() {}
}
写上注解 → 不代表能自动执行
反射才是核心逻辑。
五、反射读取注解(重点部分)
这是内容的重点,也是框架底层核心能力。
1. 获取类上的注解
Class<?> clazz = Person.class;
MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class);
System.out.println(annotation.value()); // hello
System.out.println(annotation.age()); // 22
流程图:
Class对象 → getAnnotation() → 注解实例 → 调用注解方法得到值
2. 读取字段上的注解
Field field = clazz.getDeclaredField("name");
MyAnnotation anno = field.getAnnotation(MyAnnotation.class);
System.out.println(anno.value()); // field test
注意:
字段私有也没关系,反射不管访问权限。
3. 读取方法上的注解
Method method = clazz.getDeclaredMethod("test");
MyAnnotation anno = method.getAnnotation(MyAnnotation.class);
System.out.println(anno.value()); // method test
System.out.println(anno.age()); // 99
六、注解 + 反射 = 框架底层机制
Spring 如何实现“自动装配”?
@Autowired
private UserService userService;
Spring 做的事就两步:
-
扫描所有类(反射)
-
判断字段是否标注了
@Autowiredfield.isAnnotationPresent(Autowired.class) -
如果存在 → 创建对象、注入字段
MyBatis、Swagger、Junit 也一样。
七、完整示例:反射读取自定义注解
1)自定义注解
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value();
int age() default 18;
}
2)使用注解
@MyAnnotation(value = "class value", age = 1)
public class Demo {
@MyAnnotation("field value")
private String name;
@MyAnnotation(value = "method value", age = 2)
public void test() {}
}
3)通过反射读取所有注解
public class TestReflection {
public static void main(String[] args) throws Exception {
Class<?> clazz = Demo.class;
// 1. 读取类注解
MyAnnotation c = clazz.getAnnotation(MyAnnotation.class);
System.out.println("Class: " + c.value() + ", " + c.age());
// 2. 读取字段注解
Field field = clazz.getDeclaredField("name");
MyAnnotation f = field.getAnnotation(MyAnnotation.class);
System.out.println("Field: " + f.value());
// 3. 读取方法注解
Method method = clazz.getDeclaredMethod("test");
MyAnnotation m = method.getAnnotation(MyAnnotation.class);
System.out.println("Method: " + m.value() + ", " + m.age());
}
}
输出:
Class: class value, 1
Field: field value
Method: method value, 2
八、注解与反射的高级用途
以下是实际框架会做的事情:
✔ 自动执行带注解的方法(仿 Junit)
if (method.isAnnotationPresent(MyTest.class)) {
method.invoke(obj);
}
✔ 自动生成文档(Swagger 实现原理)
✔ 自动创建对象并注入依赖(Spring IoC)
✔ ORM 映射(MyBatis:字段 → 数据库列)
九、总结
| 知识点 | 要点总结 |
|---|---|
| 注解是什么 | 给代码加信息,本身不执行逻辑 |
| 元注解 | 决定注解作用范围、生命周期 |
| 自定义注解 | @interface + 属性 + 默认值 |
| 注解存活时间 | RUNTIME 才能被反射读取 |
| 反射做什么 | 获取类、方法、字段的注解实例 |
| 获取注解的方法 | getAnnotation / isAnnotationPresent |
| 框架原理 | 都靠反射扫描注解并执行 |
790

被折叠的 条评论
为什么被折叠?



