Java 注解(Annotation)与反射:从入门到实战

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 做的事就两步:

  1. 扫描所有类(反射)

  2. 判断字段是否标注了 @Autowired

    field.isAnnotationPresent(Autowired.class)
    
  3. 如果存在 → 创建对象、注入字段

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
框架原理都靠反射扫描注解并执行

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值