Java注解的知识点
·
一、注解的核心概念(通俗理解)
可以把注解想象成:给程序元素贴的 “标签”,标签本身不直接影响程序运行,但可以被编译器、框架(如 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
}
}
}
四、注解的实际应用场景
- 编译期检查:如
@Override检查重写语法,@FunctionalInterface检查函数式接口规范; - 框架简化配置:Spring 的
@Controller、@Service、@Autowired,MyBatis 的@Mapper等,替代繁琐的 XML 配置; - 代码生成:Lombok 的
@Data自动生成 getter/setter/toString 等方法,减少重复代码; - 运行时动态处理:如自定义注解实现接口权限校验、日志记录等。
总结
- 核心本质:注解是程序的 “标记”,本身不执行逻辑,但可被编译器 / 框架读取并处理;
- 关键元注解:
@Target(作用范围)、@Retention(保留阶段,RUNTIME 是框架常用)是自定义注解的核心; - 核心能力:运行时通过反射读取注解,是注解能支撑 Spring 等框架的关键。
掌握注解的核心是理解 “标记 - 读取 - 处理” 的流程,自定义注解 + 反射的组合是 Java 高级开发(如框架封装)的基础。
更多推荐




所有评论(0)