Java — 注解
一、注解简介
Java 注解(Annotation)又称为 Java 标注,是 Java5 开始支持加入源代码的特殊语法元数据。
Java 语言中的类、方法、变量、参数和包等都可以被标注。
Java 标注可以通过反射获取标注的内容,在编译器生成 class 文件时,标注可以被嵌入到字节码中。
Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容。
二、注解作用
2.1、内置注解
Java 定义了一套注解,共有 10 个。5 个在 java.lang
包中,5 个在 java.lang.annotation
包中。
2.2、用在代码上的注解
注解 | 描述 |
---|---|
@Override | 检查该方法是否正确地重写了父类的方法。如果重写错误,会报编译错误。 |
@Deprecated | 标记废弃的方法。如果使用该方法,会报编译警告。 |
@SuppressWarnings | 提示编译器忽略注解中声明的警告。 |
@SafeVarargs | Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。 |
@FunctionalInterface | Java 8 开始支持,标识一个匿名函数或函数式接口。 |
2.3、用在其它注解上的注解
此类注解也称为元注解(meta annotation)。
注解 | 描述 |
---|---|
@Retention | 标记在什么时候保存该注解信息,用于描述注解的生命周期。 |
@Target | 标记该注解的使用范围。 |
@Documented | 标记这些注解是否包含在用户文档中。 |
@Inherited | 标记子类可以继承父类的注解。 |
@Repeatable | Java 8 开始支持,标识某注解可以在同一个声明上使用多次。 |
三、定义注解
格式:public @interface 注解名称 {}
步骤:创建注解、定义注解的参数和默认值、用上元注解配置该注解。
3.1、创建注解
示例:定义一个可用于检查字符串长度的注解
public @interface Length { }
3.2、定义参数和默认值
public @interface Length { // 最小长度 int min() default 0; // 最大长度 int max() default Integer.MAX_VALUE; // 长度不合法 String message() default "长度不合法"; }
注意:
-
注解的参数类似无参数方法。另外参数的类型可以是基本数据类型、String 类型、枚举类型、Class 类型、Annotation 类型以及这些类型的一维数组。
-
若注解中只有一个参数或这个参数是最常用的参数,应将此参数命名为 value 。在调用注解时,若参数名称是 value 且只有一个参数,则可省略参数名称。
-
可以使用 default 关键字来指定参数的默认值,推荐为每个参数都设定一个默认值。
3.3、用元注解配置注解
3.3.1、@Retention
Retention
译为保留,该注解定义了一个注解的生命周期。
参数 | 描述 |
---|---|
RetentionPolicy.RUNTIME | (运行期间有效)注解可以保留到程序运行的时候,它会被加载进入到JVM中,所以在程序运行时可以获取到它们 |
RetentionPolicy.CLASS | (编译期间有效)注解只被保留到编译进行的时候,它并不会被加载到JVM中 |
RetentionPolicy.SOURCE | (源码期间有效)注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视 |
// 运行期间有效 @Retention(RetentionPolicy.RUNTIME) public @interface Length { int min() default 0; int max() default Integer.MAX_VALUE; String message() default "长度不合法"; }
3.3.2、@Target
Target
译为目标,该是最为常用的元注解,可以指定自己能够被应用于源码中的哪些位置。
参数 | 描述 |
---|---|
ElementType.TYPE | 给一个类型进行注解,比如类、接口、枚举 |
ElementType.FIELD | 给属性进行注解 |
ElementType.METHOD | 给方法进行注解 |
ElementType.PARAMETER | 给一个方法内的参数进行注解 |
ElementType.CONSTRUCTOR | 给构造方法进行注解 |
ElementType.LOCAL_VARIABLE | 给局部变量进行注解 |
ElementType.ANNOTATION_TYPE | 给一个注解进行注解 |
ElementType.PACKAGE | 给一个包进行注解 |
// 只用用于类属性或局部变量上 @Target({ElementType.FIELD, ElementType.LOCAL_VARIABLE}) public @interface Length { int min() default 0; int max() default Integer.MAX_VALUE; String message() default "长度不合法"; }
3.3.3、@Documented
Documented
译为文档,标注了此注解的注解,能够将注解中的元素包含到 Javadoc 中去。
// 将该注解元素添加到JavaDoc中 @Documented public @interface Length { int min() default 0; int max() default Integer.MAX_VALUE; String message() default "长度不合法"; }
3.3.4、@Inherited
Inherited
译为继承,使用该注解定义子类是否可继承父类定义的注解。
@Inherited
仅针对 @Target(ElementType.TYPE)
类型的注解有效,并且仅针对类的继承有效,对接口的继承无效。
// 使用该注解的类,其子类默认继承该注解(仅针对类的继承有效) @Inherited // 给一个类型进行注解,类、接口、枚举等 @Target(ElementType.TYPE) public @interface Length { int min() default 0; int max() default Integer.MAX_VALUE; String message() default "长度不合法"; }
此时一个类用到了该注解
@Length(min = 2, max = 16, message = "昵称长度2~16之间") public class Pet {}
其子类默认继承了该注解
// 相当于继承了@Length public class Cat extends Pet {}
3.3.5、@Repeatable
Repeatable
译为可重复,使用该元注解可以定义注解是否可重复。
// 作用于类的属性上 @Target(ElementType.FIELD) // 注解Role注解,在类的属性上可使用多个Role注解 @Repeatable(Roles.class) public @interface Role { String value() default ""; }
// 作用于类的属性上 @Target(ElementType.FIELD) public @interface Roles { Role[] value(); }
@Repeatable
元注解标注了 @Role
,而 @Repeatable
后面括号中的类相当于一个容器注解。
按照规定,它里面必须要有一个 value 的属性,属性类型是一个被 @Repeatable
注解标注过的注解数组。
经过 @Repeatable
修饰后,在某个类型声明处,就可以添加多个@Role
注解:
public class Student { @Role("学习委员") @Role("体育委员") private String name; }
四、处理注解
4.1、示例1
需求:使用 @length
注解判断学生姓名长度是否合法。
示例:
// 运行期间有效 @Retention(RetentionPolicy.RUNTIME) // 作用于类的属性上 @Target({ElementType.FIELD}) public @interface Length { // 最小长度 int min() default 0; // 最大长度 int max() default Integer.MAX_VALUE; // 提示信息 String message() default "长度不合法"; }
public class Student { @Length(min = 1, max = 3, message = "名称超长") private String name; public Student(String name) { this.name = name; } public String getName() { return name; } public static void main(String[] args) throws NoSuchFieldException { Student student = new Student("上官飞燕"); // 判断name属性上length注解是否存在 boolean lengthPresent = student.getClass().getDeclaredField("name").isAnnotationPresent(Length.class); if (lengthPresent) { // 获取注解内容 Length length = student.getClass().getDeclaredField("name").getAnnotation(Length.class); // 使用注解信息校验名称是否合法 if (length.min() <= student.getName().length() && student.getName().length() <= length.max()) { System.out.println("名称合法"); } else { System.out.println(length.message() + "," + "合法长度:" + length.min() + "~" + length.max() + "。" + "当前长度:" + student.getName().length()); } } else { System.out.println("Student.name属性上没有找到@Length注解"); } } }
运行:
名称超长,合法长度:1~3。当前长度:4
4.2、示例2
需求:使用 @Repeatable
注解获取学生所有的职位。
示例:
// 运行期间有效 @Retention(RetentionPolicy.RUNTIME) // 作用于类的属性上 @Target(ElementType.FIELD) public @interface Roles { Role[] value(); }
// 运行期有效 @Retention(RetentionPolicy.RUNTIME) // 作用与类的属性上 @Target({ElementType.FIELD}) // 注解Role注解,在类的属性上可使用多Role注解 @Repeatable(Roles.class) public @interface Role { String value() default ""; }
public class Student { @Role("学习委员") @Role("体育委员") private String name; public Student(String name) { this.name = name; } public String getName() { return name; } public static void main(String[] args) throws NoSuchFieldException { Student student = new Student("王五"); // 判断name属性上@Role注解是否存在 Role[] roles = student.getClass().getDeclaredField("name").getAnnotationsByType(Role.class); if (roles.length == 0) { System.out.println("Student.name属性上没有找到@Role注解"); } else { // 获取注解内容 for (Role role : roles) { System.out.println(student.getName() + " = " + role.value()); } } } }
运行:
王五 = 学习委员 王五 = 体育委员
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~