Java
注解的定义 & 作用
概念
注解(Annotation)是 JDK 1.5 新增特性,属于一种特殊标记注释,用来修饰类、方法、成员变量、参数、构造器等,在编译阶段 / 运行阶段被程序读取并解析使用。 分为两类:
- JDK 内置注解:
@Override、@Deprecated、@WebServlet等; - 开发者自定义注解。
注解生效的两种解析方式
注解本身只是标记,必须被解析才能发挥作用:
- 编译期扫描解析 编译器编译代码时识别注解并处理。 例:
@Override,编译阶段校验该方法是否正确重写了父类方法,写错直接编译报错。 - 运行期反射解析 框架主流方式(Spring
@Component、@Value、MyBatis 注解等),程序运行时利用反射读取注解上的配置信息并执行逻辑。
注解两大核心作用
- 告知编译器语法校验规则;
- 替代传统 XML/Properties 配置文件,简化配置(SSM、SpringBoot 核心思想)。
内置注解示例
// 校验是否重写父类方法
@Override
public String toString() {
return super.toString();
}
// Servlet注解,替代web.xml配置
@WebServlet("/student")
public class StudentServlet extends HttpServlet {
}
自定义注解
自定义注解可以在类、字段、方法上附加自定义配置信息,搭配反射读取注解数据。
元注解(修饰注解的注解)
用来规定「自定义注解能写在哪些位置」「存活到哪个阶段」。
@Target:限定注解的生效位置
@Target({
TYPE, // 类、接口、枚举
FIELD, // 成员字段
METHOD, // 普通方法
PARAMETER, // 方法形参
CONSTRUCTOR, // 构造方法
LOCAL_VARIABLE // 局部变量
})
@Retention:限定注解生命周期(存活阶段)
@Retention(RetentionPolicy.SOURCE) // 仅源码阶段存在,编译成class后丢弃
@Retention(RetentionPolicy.CLASS) // 保存到class字节码,运行时JVM丢弃(默认生命周期)
@Retention(RetentionPolicy.RUNTIME) // 运行时期依旧保留,可以通过反射获取(框架自定义注解必选)
完整自定义注解案例
步骤1:定义注解 @Author
import java.lang.annotation.*;
// 该注解可以标注在类、成员变量、方法上
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
// 运行时保留,支持反射读取
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
// 注解属性,可设置默认值
String name() default "";
int age() default 20;
// 特殊属性名 value:使用注解时,如果只赋值value,可以省略value=
String[] value() default {};
}
步骤2:使用自定义注解
// 完整赋值写法
@Author(name = "zhao", age = 12, value = "男")
public class AuthorDemo {
// 全部使用默认属性值
@Author
private String str;
@Author(name = "zhangsan", age = 23, value = {"男", "女"})
public void add() {
}
}
简写规则:注解只有 value 一个属性时,赋值可省略 value=
@Author("男")
// 等价
@Author(value = "男")
// 数组写法
@Author({"男", "女"})
步骤3:通过反射解析注解(读取注解中的数据)
import org.junit.Test;
import java.lang.reflect.Method;
import java.util.Arrays;
public class TestAnnotation {
@Test
public void test1() throws NoSuchMethodException {
// 1. 获取类Class对象
Class<AuthorDemo> clazz = AuthorDemo.class;
// 2. 获取标注在类上的 @Author 注解
Author typeAuthor = clazz.getAnnotation(Author.class);
System.out.println(typeAuthor.value()[0]);
// 3. 获取add方法对应的Method对象
Method method = clazz.getDeclaredMethod("add");
// 4. 获取方法上的注解
Author methodAuthor = method.getAnnotation(Author.class);
System.out.println(methodAuthor.name()); // zhangsan
System.out.println(methodAuthor.age()); // 23
System.out.println(Arrays.toString(methodAuthor.value())); // [男, 女]
}
}
补充规则
- 自定义注解内可以定义多个属性,属性可以添加
default默认值;
- 注解生命周期想要被反射读取,必须设置
@Retention(RetentionPolicy.RUNTIME);
getAnnotation(注解.class):获取目标上指定类型注解,返回注解实例;
- 元注解就是修饰注解的注解,用来定义注解:
| 元注解 | 作用 |
|---|---|
@Target |
指定注解可以用在什么地方:TYPE(类)、FIELD(字段)、METHOD(方法)、PARAMETER(参数)、CONSTRUCTOR(构造) |
@Retention |
指定注解保留到什么时候:SOURCE(编译丢弃)、CLASS(编译保留不加载)、RUNTIME(运行保留,可以反射读取) |
@Documented |
注解信息会被 javadoc 提取,生成 JavaDoc 文档时保留注解 |
@Inherited |
修饰的注解会被子类继承 |