006.注解

引言:开发中有注释,注释和注解有没有关系呢?其实两个是有关系的,只是针对的对象不一样,注释是给开发者看的;而注解是给程序看的,程序可以根据不同的注解来做不同的业务逻辑。

1. 什么是注解?

注解(Annotation) 是 JDK 5 引入的语法,本质是给代码贴标签------标签本身不影响代码执行,但能被编译器、框架、运行时反射机制读取并做出相应处理。

一句话:注解是**"代码的使用说明书"**------告诉别人"这段代码是用来干嘛的、什么时候用"。

Java 内置了三类常用注解:

注解 作用
@Override 告诉编译器"我要重写父类方法"
@Deprecated 告诉别人"这个方法已过时,不推荐用"
@SuppressWarnings 告诉编译器"别再警告了",注解中的参数参考附录表A

但更强大的,是自定义注解

2. 为什么需要注解?

举个现实例子:

去超市买东西,每件商品都贴着标签------"生产日期 2026-01-01"、"保质期 12 个月"、"产地:云南"。这些标签不改变商品本身,但消费者和超市系统可以通过标签快速识别商品属性

注解就是代码的"商品标签":

  • 商品 = 类、方法、字段

  • 标签 = 注解

  • 看标签的人 = 编译器 / 框架 / 反射机制

以前写代码要在 XML 里配置这些"标签"(如 Spring 早期),现在直接写在代码上,更直观。

3. 代码示例:自定义一个"员工级别"注解

① 定义注解

Java 复制代码
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)  // 注解保留到运行时
@Target(ElementType.FIELD)          // 只能贴在字段上
public @interface Level {
    int value();        // 必填:级别数字
    String desc() default "普通员工";  // 选填:级别描述
}

② 使用注解

Java 复制代码
public class Employee {
    @Level(value = 5, desc = "高级工程师")
    private String engineer;

    @Level(value = 8, desc = "技术总监")
    private String director;

    @Level(3)  // 只有 value 时可以省略名字
    private String junior;
}

③ 通过反射读取注解

Java 复制代码
public class TestAnnotation {
    public static void main(String[] args) {
        Class<?> clazz = Employee.class;
        for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {
            Level level = field.getAnnotation(Level.class);
            if (level != null) {
                System.out.println(field.getName() + " → 级别 "
                        + level.value() + "(" + level.desc() + ")");
            }
        }
    }
}

④ 测试结果

Plain 复制代码
engineer → 级别 5(高级工程师)
director → 级别 8(技术总监)
junior → 级别 3(普通员工)

4. 元注解:注解的"注解"

@Retention@Target元注解(meta-annotation),用来"注解"注解本身。

@Retention:注解能活多久

取值 含义 典型用途
SOURCE 只在源码期,编译后丢弃 给 IDE 看(如 @Override
CLASS 编译到 class 文件,运行时不加载 默认值,框架字节码增强用
RUNTIME 运行时也能读到 反射读取、自定义框架

@Target:注解能贴在哪

取值 可贴位置
FIELD 字段
METHOD 方法
TYPE 类、接口、枚举
PARAMETER 方法参数
CONSTRUCTOR 构造方法
LOCAL_VARIABLE 局部变量

可以多选:@Target({ElementType.FIELD, ElementType.METHOD})

5. 反例对比:XML 配置 vs 注解配置

以"在 Spring 中注册一个 Bean"为例。

❌ 反例:纯 XML 配置(Spring 早期)

XML 复制代码
<!-- applicationContext.xml -->
<beans>
    <bean id="userService" class="com.example.UserService">
        <property name="userDao" ref="userDao"/>
    </bean>
    <bean id="userDao" class="com.example.UserDao"/>
</beans>

痛点:Bean 类改了名字/属性,XML 必须同步改,否则运行不起来。配置文件越来越臃肿。

✅ 正例:注解配置(Spring Boot 现在)

Java 复制代码
@Service  // 直接在类上贴标签:我是 Service
public class UserService {
    @Autowired  // 直接在字段上贴:帮我注入 userDao
    private UserDao userDao;
}

效果 :Bean 的元信息和代码写在同一处,改一处就生效,IDE 还能跳转提示。

6. 扩展场景:注解在框架中的应用

① Spring 全家桶

注解 作用
@Component / @Service / @Repository 把类标记为 Spring 容器管理的 Bean
@Autowired 自动注入依赖
@RequestMapping / @GetMapping 把 URL 路径映射到方法
@Transactional 给方法加事务控制

原理:Spring 启动时扫描所有类,反射读取这些注解,自动建对象、注入依赖、注册路由。

② MyBatis

Java 复制代码
public interface UserMapper {
    @Select("SELECT * FROM user WHERE id = #{id}")
    User findById(int id);

    @Insert("INSERT INTO user(name) VALUES(#{name})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    void insert(User user);
}

没写实现类 ,但 MyBatis 运行时通过动态代理 + 反射读注解,自动帮你生成 SQL 执行代码。

总结:注解让框架从"读 XML 配置"变成"读代码标签",开发效率大幅提升。

7. 什么时候用注解?

:框架配置(Spring/MyBatis)、数据校验(@NotNull)、权限控制(@RequiresPermission)、单元测试标记(@Test)、自定义业务标签(如日志埋点)。

不用:复杂业务逻辑(注解本质只是数据,不适合装复杂规则)、需要频繁修改的配置(写死在注解里改一次要重新编译)。

👋 一句话总结注解:注解是"给代码贴标签",编译器和框架通过反射读标签,实现"配置即代码"。


三、课堂小结

知识点 核心一句话 关键代码/语法
自定义注解 @interface 定义 @Retention + @Target
元注解 注解的"注解" RUNTIME + FIELD
框架应用 反射读注解 → 自动配置 @Component@Select

记忆口诀

  • 泛型:编译器帮你管类型

  • 注解:框架帮你读标签

相关推荐
liuchangng1 小时前
Jev 模型研究:从生成式大模型到决策式模型——System One、RLCD 校准与采用边界
java·javascript·人工智能·python·深度学习
GPU实战笔记1 小时前
本地跑不动 llama.cpp,临时租云 GPU 怎么搭?从启动服务到环境复用
java·服务器·网络·人工智能·深度学习·llama
撸串-研究生1 小时前
SSM + Vue 线上作业批改系统:在线答题、文件提交与教师批改闭环90608
java·ssm·在线答题·作业批改·文件提交
一 乐1 小时前
养老院管理系统|基于springboot + vue养老院管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·毕业设计
wang_shu_mo_ran1 小时前
Spring MVC 常用注解和用法(二)——url,cookie,session
java·mvc
杨运交1 小时前
[074][示例]基于Redisson的分布式锁在定时任务中的实践与异常模拟
java·后端·spring
小刘在重生~1 小时前
Java Lock 显式锁案例|ReentrantLock 解决多线程安全问题(超详细实战)
java·笔记·面试
步行cgn1 小时前
Spring 中完整的 Scope 选项详解
java·后端·spring
hai_android2 小时前
Android MeasureSpec 详解
android·java·kotlin