注解的基本概念
注解(Annotation)就像一种“标记”,你可以把它放在代码的任何地方(类、方法、字段、参数等),它本身不执行任何操作,但它为其他程序(如编译器、IDE、框架)提供了信息。

Java 内置了许多注解,
@Override: 告诉编译器这个方法是要重写父类的方法。@Deprecated: 标记某个方法或类已过时,不推荐使用。@SuppressWarnings: 告诉编译器忽略某些警告。
定义一个自定义注解
要定义自己的注解,你需要使用 @interface 关键字,一个注解的定义看起来像一个接口。
基本语法
public @interface MyAnnotation {
// 在这里定义注解的成员
}
关键组成部分
一个完整的注解定义通常包含以下几个部分:
- 注解名称: 使用
@interface定义。 - 成员: 注解可以包含一些成员,它们看起来像抽象方法,成员的类型必须是基本类型、String、Class、枚举、注解或它们的数组。
- 默认值: 成员可以有默认值,使用
default关键字指定。 - 元注解: 用于注解其他注解的注解,用来控制注解的行为。
详细步骤与示例
让我们通过一个实际的例子来学习如何定义和使用一个注解。

第1步:定义注解本身
假设我们想创建一个用于标记方法作者和创建日期的注解 @Author。
Author.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 1. @Target: 指定这个注解可以应用在哪些元素上
// ElementType.METHOD 表示它只能用在方法上
@Target(ElementType.METHOD)
// 2. @Retention: 指定这个注解的保留策略
// RetentionPolicy.RUNTIME 表示注解会在运行时保留,可以通过反射读取
@Retention(RetentionPolicy.RUNTIME)
// 3. 定义注解的成员
// value() 是一个特殊的成员名,使用时可以省略 "value="
public @interface Author {
String value(); // 成员,类型为 String,没有默认值
String date() default "2025-01-01"; // 成员,类型为 String,有默认值
}
代码解析:
-
@Target(元注解):
(图片来源网络,侵删)- 作用:限定注解的使用范围。
ElementType.METHOD:表示@Author只能被用在方法上。- 其他可选值:
TYPE(类、接口、枚举),FIELD(字段),PARAMETER(参数) 等,可以指定多个,如@Target({ElementType.METHOD, ElementType.TYPE})。
-
@Retention(元注解):- 作用:定义注解的生命周期,即注解会被保留到什么时候。
RetentionPolicy.SOURCE:只在源码中存在,编译后就被丢弃。RetentionPolicy.CLASS:源码和.class文件中都存在,但在运行时被 JVM 丢弃,这是默认策略。RetentionPolicy.RUNTIME:源码、.class文件和运行时都存在,只有这个级别的注解才能被反射机制读取,如果你需要在运行时处理注解(通过 Spring、MyBatis 等框架),就必须使用这个策略。
-
value()和date():- 这是
@Author注解的两个成员。 String value(): 这是一个特殊的成员,名为value,在使用注解时,如果只设置一个值,并且这个值的名称是value,那么可以省略value=。@Author("张三")。String date() default "2025-01-01": 这个成员有一个默认值,如果使用注解时不提供date的值,就会自动使用这个默认值。
- 这是
第2步:使用自定义注解
现在我们可以在代码中使用刚刚定义的 @Author 注解了。
UserService.java
public class UserService {
@Author(value = "李四") // date 会使用默认值 "2025-01-01"
public void createUser(String username) {
System.out.println("正在创建用户: " + username);
}
@Author(value = "王五", date = "2025-10-27") // 同时指定 value 和 date
public void deleteUser(String username) {
System.out.println("正在删除用户: " + username);
}
// 由于 value 是特殊成员,可以省略 value=
@Author("赵六")
public void updateUser(String username, String newInfo) {
System.out.println("正在更新用户: " + username);
}
}
第3步:通过反射处理注解(读取注解信息)
注解本身没有作用,关键在于如何读取它,我们通过 Java 的反射 API 来读取 @Author 注解的信息。
AnnotationProcessor.java
import java.lang.reflect.Method;
public class AnnotationProcessor {
public static void main(String[] args) {
// 1. 获取 UserService 类的 Class 对象
Class<?> userServiceClass = UserService.class;
// 2. 获取所有声明的方法
Method[] methods = userServiceClass.getDeclaredMethods();
System.out.println("------ 正在处理 UserService 中的方法 ------");
// 3. 遍历每个方法
for (Method method : methods) {
// 4. 检查方法上是否有 @Author 注解
if (method.isAnnotationPresent(Author.class)) {
// 5. 如果存在,获取该注解的实例
Author authorAnnotation = method.getAnnotation(Author.class);
// 6. 从注解实例中获取成员的值
String authorName = authorAnnotation.value();
String creationDate = authorAnnotation.date();
// 7. 打印信息
System.out.println("方法名: " + method.getName());
System.out.println(" - 作者: " + authorName);
System.out.println(" - 创建日期: " + creationDate);
System.out.println("-------------------------------------");
}
}
}
}
运行结果:
------ 正在处理 UserService 中的方法 ------
方法名: createUser
- 作者: 李四
- 创建日期: 2025-01-01
-------------------------------------
方法名: deleteUser
- 作者: 王五
- 创建日期: 2025-10-27
-------------------------------------
方法名: updateUser
- 作者: 赵六
- 创建日期: 2025-01-01
-------------------------------------
高级特性:注解继承
有时候我们希望一个类上的注解能被它的所有方法继承,Java 8 引入了 @Inherited 元注解来实现这一点。
InheritedAnnotation.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE) // 只能用在类上
@Retention(RetentionPolicy.RUNTIME)
@Inherited // 表示这个注解可以被继承
public @interface InheritedAnnotation {
String value();
}
BaseService.java
@InheritedAnnotation(value = "基础服务")
public class BaseService {
public void commonMethod() {
System.out.println("这是一个通用方法");
}
}
DerivedService.java
// 继承自 BaseService
public class DerivedService extends BaseService {
@Override
public void commonMethod() {
System.out.println("这是 DerivedService 的方法");
}
}
测试继承性:
// 在另一个类中测试 InheritedAnnotation annotation = DerivedService.class.getAnnotation(InheritedAnnotation.class); System.out.println(DerivedService.class.getSimpleName() + " 上的注解值: " + annotation.value()); // 输出: DerivedService 上的注解值: 基础服务
注意:@Inherited 只对类有效,对接口无效,并且子类不会继承父类方法的注解,只会继承父类类本身的注解。
- 定义注解:使用
@interface关键字。 - 添加成员:在注解内部定义抽象方法来表示成员。
- 提供默认值:使用
default关键字为成员设置默认值。 - 使用元注解:
@Target:控制注解的使用位置。@Retention:控制注解的生命周期(RUNTIME是反射的关键)。@Documented:表示注解会包含在 Javadoc 中。@Inherited:表示注解可以被继承。
- 使用注解:像
@Override一样,将注解放在代码元素前。 - 处理注解:通过 Java 反射 API(
Class.getAnnotation(),Method.isAnnotationPresent()等)在运行时读取注解信息,并执行相应的逻辑。
掌握自定义注解是理解现代 Java 框架(如 Spring, Hibernate, JUnit)工作原理的基础,因为它正是这些框架实现“零配置”和“声明式编程”的核心技术。
