一、注解的核心概念(通俗理解)

可以把注解想象成:给程序元素贴的 “标签”,标签本身不直接影响程序运行,但可以被编译器、框架(如 Spring)、工具(如 Lombok)读取,根据标签内容做额外处理。

  • 比如 @Override 是告诉编译器:“这个方法是重写父类的,帮我检查语法是否正确”;
  • 比如 @GetMapping("/user") 是告诉 Spring:“这个方法处理 GET 请求,路径是 /user”。
二、Java 内置的常用注解

Java 提供了几个基础注解,覆盖最常用的场景:

表格

注解作用
@Override标记方法重写父类 / 接口的方法,编译器会检查重写语法(如方法名、参数是否匹配)
@Deprecated标记方法 / 类已过时,使用时编译器会给出警告
@SuppressWarnings抑制编译器警告(如忽略未使用变量、不安全类型转换等)
@FunctionalInterface标记函数式接口(只有一个抽象方法的接口),编译器会检查接口规范
@SafeVarargs抑制可变参数的泛型类型安全警告

示例:内置注解的使用

java

运行

import java.util.ArrayList;
import java.util.List;

public class AnnotationDemo {
    // 1. @Override:检查方法重写
    @Override
    public String toString() {
        return "AnnotationDemo";
    }

    // 2. @Deprecated:标记方法过时
    @Deprecated
    public void oldMethod() {
        System.out.println("这个方法已过时,建议使用newMethod");
    }

    // 3. @SuppressWarnings:抑制警告(这里抑制未使用变量的警告)
    @SuppressWarnings("unused")
    public void suppressWarningDemo() {
        int unusedVar = 10; // 不会触发编译器警告
    }

    // 4. @FunctionalInterface:标记函数式接口
    @FunctionalInterface
    interface MyFunctionalInterface {
        void doSomething();
        // 允许有默认方法,不影响函数式接口特性
        default void defaultMethod() {}
    }

    public static void main(String[] args) {
        AnnotationDemo demo = new AnnotationDemo();
        demo.oldMethod(); // 编译器会提示:方法已过时
    }
}
三、自定义注解(核心重点)

如果内置注解满足不了需求,可以自定义注解,步骤如下:

1. 定义注解(使用 @interface 关键字)

java

运行

import java.lang.annotation.*;

// 自定义注解:@MyAnnotation
@Target({ElementType.METHOD, ElementType.TYPE}) // 注解可作用于方法、类/接口
@Retention(RetentionPolicy.RUNTIME) // 注解保留到运行时(可被反射读取)
@Documented // 注解会被javadoc文档生成工具包含
public @interface MyAnnotation {
    // 注解的属性(类似方法定义,有默认值)
    String value() default "默认值"; // value是特殊属性,使用时可省略属性名
    int age() default 18;
}
2. 核心元注解(修饰注解的注解)

元注解是 Java 提供的专门用于定义注解的注解,必须掌握:

表格

元注解作用
@Target指定注解能作用的程序元素(如 TYPE = 类 / 接口,METHOD = 方法,FIELD = 变量)
@Retention指定注解的保留阶段(关键!):- SOURCE:仅保留在源码,编译后丢弃(如 @Override)- CLASS:保留到编译后的 class 文件,运行时丢弃(默认)- RUNTIME:保留到运行时,可通过反射读取(框架常用)
@Documented注解会被 javadoc 工具生成到文档中
@Inherited注解可被子类继承(仅作用于类级别的注解)
@Repeatable允许注解在同一个元素上重复使用(Java 8 新增)
3. 使用自定义注解

java

运行

// 作用于类(使用默认属性值)
@MyAnnotation
public class MyClass {
    // 作用于方法(指定属性值,value可省略属性名)
    @MyAnnotation(value = "自定义值", age = 20)
    public void myMethod() {
        System.out.println("使用自定义注解的方法");
    }
}
4. 读取注解(反射实现)

注解的核心价值是 “被程序读取并处理”,运行时读取注解必须用反射

java

运行

import java.lang.reflect.Method;

public class ReadAnnotation {
    public static void main(String[] args) throws NoSuchMethodException {
        // 1. 获取类的Class对象
        Class<MyClass> clazz = MyClass.class;

        // 2. 读取类上的注解
        if (clazz.isAnnotationPresent(MyAnnotation.class)) {
            MyAnnotation classAnnotation = clazz.getAnnotation(MyAnnotation.class);
            System.out.println("类注解的value:" + classAnnotation.value()); // 输出:默认值
            System.out.println("类注解的age:" + classAnnotation.age()); // 输出:18
        }

        // 3. 读取方法上的注解
        Method method = clazz.getMethod("myMethod");
        if (method.isAnnotationPresent(MyAnnotation.class)) {
            MyAnnotation methodAnnotation = method.getAnnotation(MyAnnotation.class);
            System.out.println("方法注解的value:" + methodAnnotation.value()); // 输出:自定义值
            System.out.println("方法注解的age:" + methodAnnotation.age()); // 输出:20
        }
    }
}
四、注解的实际应用场景
  1. 编译期检查:如 @Override 检查重写语法,@FunctionalInterface 检查函数式接口规范;
  2. 框架简化配置:Spring 的 @Controller@Service@Autowired,MyBatis 的 @Mapper 等,替代繁琐的 XML 配置;
  3. 代码生成:Lombok 的 @Data 自动生成 getter/setter/toString 等方法,减少重复代码;
  4. 运行时动态处理:如自定义注解实现接口权限校验、日志记录等。

总结

  1. 核心本质:注解是程序的 “标记”,本身不执行逻辑,但可被编译器 / 框架读取并处理;
  2. 关键元注解@Target(作用范围)、@Retention(保留阶段,RUNTIME 是框架常用)是自定义注解的核心;
  3. 核心能力:运行时通过反射读取注解,是注解能支撑 Spring 等框架的关键。

掌握注解的核心是理解 “标记 - 读取 - 处理” 的流程,自定义注解 + 反射的组合是 Java 高级开发(如框架封装)的基础。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐