您提到的 "attribute" 在注解的上下文中,通常指的是注解的元素 或 成员,我们可以把它理解为“配置项”或“参数”。

什么是注解?
注解是 Java 的一种元数据,它不是程序本身,但可以用来修饰程序(类、方法、变量、包等),为代码提供一些额外的信息,就像给代码贴上“标签”一样。
它的核心作用是:
- 编译检查:
@Override,告诉编译器这个方法是重写父类的方法,如果写错了,编译器会报错。 - 配置和部署:
@SpringBootApplication、@RestController,在 Spring 框架中,这些注解用来标记一个类是应用程序的入口或是一个 Web 控制器。 - 代码生成:
@Data(Lombok),在编译时自动为类生成 getter、setter、toString 等方法。 - 运行时处理:
@Deprecated,标记一个方法或类已过时,或者在运行时通过反射获取注解信息,实现某些逻辑。
如何定义一个注解?
使用 @interface 关键字来定义一个注解,一个注解定义看起来像一个接口。
// 定义一个名为 "MyAnnotation" 的注解
public @interface MyAnnotation {
}
这是一个最简单的注解,它没有任何“属性”。

如何为注解添加“属性”(Elements)?
注解的“属性”在定义时,是以“无参方法”的形式出现的,方法名就是属性名,返回值类型就是属性的类型。
基本语法:
public @interface MyAnnotation {
// 定义一个名为 "value" 的属性,类型为 String
String value();
// 定义一个名为 "count" 的属性,类型为 int,有默认值 10
int count() default 10;
// 定义一个名为 "enabled" 的属性,类型为 boolean,有默认值 true
boolean enabled() default true;
}
关键点:
- 属性类型:可以是基本类型(
int,float,boolean等)、String、Class、枚举类型,或者它们的一维数组。 - 默认值:使用
default关键字为属性提供默认值,如果一个属性有默认值,在使用该注解时就可以不指定这个属性。 - 特殊属性
value:如果一个注解只有一个名为value的属性,那么在使用时,可以直接赋值,而不需要写成value = "xxx"的形式。
如何使用注解?
在要修饰的元素前面加上 和注解名称即可。

示例 1:使用带属性的注解
假设我们有上面定义的 MyAnnotation:
@MyAnnotation(
value = "This is a class", // 为 value 属性赋值
count = 5, // 为 count 属性赋值(覆盖默认值 10)
enabled = true // 使用默认值 true,也可以不写
)
public class MyClass {
@MyAnnotation(value = "This is a method", count = 100)
public void myMethod() {
// ...
}
}
示例 2:使用特殊属性 value
假设我们定义一个简单的注解:
public @interface SimpleAnnotation {
String value();
}
使用时:
// 写法一:标准写法
@SimpleAnnotation(value = "Hello")
public class TestClass {}
// 写法二:简化写法(因为只有一个 value 属性)
@SimpleAnnotation("Hello")
public class TestClass {}
元注解:如何控制注解本身?
元注解是用于修饰其他注解的注解,它们可以控制注解的生命周期、使用范围等。
常用的元注解有:
-
@Target:定义注解可以修饰哪些程序元素。
ElementType.TYPE:类、接口、枚举ElementType.METHOD:方法ElementType.FIELD:字段(成员变量)ElementType.PARAMETER:参数ElementType.CONSTRUCTOR:构造器ElementType.ANNOTATION_TYPE:注解ElementType.PACKAGE:包ElementType.LOCAL_VARIABLE:局部变量ElementType.RECORD_COMPONENT:记录组件 (Java 14+)
-
@Retention:定义注解的生命周期。
RetentionPolicy.SOURCE:只在源码中存在,编译时被丢弃。RetentionPolicy.CLASS:在.class文件中存在,但运行时被 JVM 丢弃(默认策略)。RetentionPolicy.RUNTIME:在运行时也存在,可以通过反射读取,这是最强大的策略。
-
@Documented:表示该注解会被包含在 Javadoc 文档中。
-
@Inherited:表示被注解的类会被其子类继承。
示例:定义一个只能在类和方法上使用,并且在运行时可通过反射访问的注解
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD}) // 可以用在类和方法上
@Retention(RetentionPolicy.RUNTIME) // 运行时有效
@Documented // 会包含在 Javadoc 中
public @interface MyRuntimeAnnotation {
String author();
String date() default "2025-01-01";
}
运行时处理:通过反射读取注解信息
只有 RetentionPolicy.RUNTIME 的注解才能在运行时被读取,这通常通过 Java 反射 API 来实现。
示例:
// 1. 定义一个运行时注解
@Retention(RetentionPolicy.RUNTIME)
@interface MyRuntimeAnnotation {
String value();
}
// 2. 在类上使用该注解
@MyRuntimeAnnotation("This is a test class")
public class TestAnnotationReflection {
public static void main(String[] args) {
try {
// 3. 获取 TestAnnotationReflection 类的 Class 对象
Class<?> clazz = TestAnnotationReflection.class;
// 4. 获取类上的注解
MyRuntimeAnnotation annotation = clazz.getAnnotation(MyRuntimeAnnotation.class);
// 5. 检查注解是否存在并打印信息
if (annotation != null) {
System.out.println("Found annotation on class: " + annotation.annotationType().getName());
System.out.println("Annotation value: " + annotation.value());
} else {
System.out.println("No annotation found on the class.");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出:
Found annotation on class: MyRuntimeAnnotation
Annotation value: This is a test class
| 概念 | 解释 | 示例 |
|---|---|---|
| 注解 | 一种元数据,用于修饰代码。 | @Override, @Test |
| 定义 | 使用 @interface 关键字。 |
public @interface MyAnnotation {} |
| 属性 | 在注解内部定义的无参方法。 | String name(); int age() default 18; |
| 使用 | 在代码前加上 和注解名。 | @MyAnnotation(name = "Alice") |
| 元注解 | 修饰注解的注解,控制其行为。 | @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) |
| 处理 | 通过反射在运行时读取 RUNTIME 级别的注解。 |
clazz.getAnnotation(MyAnnotation.class) |
希望这个详细的解释能帮助你完全理解 Java 中的注解和它的“属性”!
