Java 注解详解与自定义实践
Java 注解(Annotation)是一种声明式语法,允许开发者为代码添加附加的元数据。这些元数据本身不直接改变代码的执行逻辑,但可以被编译器、开发工具或运行时环境读取和利用,以实现编译时检查、代码生成或运行时行为增强等功能。
元注解
Java 提供了一组特殊的注解,称为元注解(Meta-Annotations),它们用于定义和管理其他注解。主要的元注解包括:
-
@Retention: 定义了注解的生命周期。SOURCE: 注解仅在源代码层面存在,会被编译器忽略。CLASS: 注解被写入到类文件中,但不会在运行时加载(默认行为)。RUNTIME: 注解在运行时仍然可用,可以通过反射机制访问。
-
@Target: 指定注解可以应用的程序元素类型。TYPE: 应用于类、接口(包括注解类型)或枚举。FIELD: 应用于类或枚举的字段(实例变量)。METHOD: 应用于方法声明。PARAMETER: 应用于方法的参数。CONSTRUCTOR: 应用于构造方法。LOCAL_VARIABLE: 应用于局部变量。PACKAGE: 应用于包声明。
-
@Documented: 表明被注解的元素应该被 Javadoc 工具提取,并在生成的文档中包含该注解信息。 -
@Inherited: 指示如果一个类被注解了 `@Inherited` 注解,并且该类被继承,那么它的子类也会自动继承该注解。
自定义注解的创建与使用
下面我们将创建一个自定义注解,并展示如何在代码中使用它,以及如何通过反射来读取注解信息。
1. 定义自定义注解
创建一个名为 ApiInfo 的注解,用于记录 API 的相关信息。该注解将被保留到运行时,并且可以应用于类和方法。
package com.example.annotations;
import java.lang.annotation.*;
/**
* 自定义API信息注解
* @Retention(RetentionPolicy.RUNTIME) - 确保在运行时可被反射访问
* @Target({ElementType.TYPE, ElementType.METHOD}) - 可用于类和方法
* @Documented - 包含在API文档中
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
public @interface ApiInfo {
/**
* API的名称
* @return API名称
*/
String name() default "";
/**
* API的版本号
* @return 版本号
*/
String version() default "1.0";
/**
* API是否启用
* @return true表示启用,false表示禁用
*/
boolean enabled() default true;
}
2. 在代码中使用自定义注解
现在,我们将 ApiInfo 注解应用到类和方法上。
package com.example.service;
import com.example.annotations.ApiInfo;
/**
* 用户服务类,标记API信息
* @ApiInfo(name = "UserService", version = "v2") - 应用类级别的注解
*/
@ApiInfo(name = "UserService", version = "v2")
public class UserService {
private String currentStatus = "Idle";
/**
* 获取用户信息的方法
* @ApiInfo(name = "getUserDetails", enabled = true) - 应用方法级别的注解,覆盖默认值
* @param userId 用户ID
* @return 用户详情字符串
*/
@ApiInfo(name = "getUserDetails", enabled = true)
public String getUserDetails(int userId) {
System.out.println("正在获取用户ID为 " + userId + " 的详细信息...");
this.currentStatus = "Fetching User: " + userId;
return "UserDetails for User " + userId;
}
/**
* 更新用户状态的方法
*/
public void updateUserStatus(String status) {
System.out.println("更新用户状态为: " + status);
this.currentStatus = status;
}
public String getCurrentStatus() {
return currentStatus;
}
}
3. 通过反射处理注解
创建一个处理器类,利用 Java 反射机制来读取和解析 ApiInfo 注解。
package com.example.processor;
import com.example.annotations.ApiInfo;
import com.example.service.UserService;
import java.lang.reflect.Method;
public class AnnotationReader {
public static void main(String[] args) {
Class> userServiceClass = UserService.class;
// 检查并读取类级别的注解
if (userServiceClass.isAnnotationPresent(ApiInfo.class)) {
ApiInfo classAnnotation = userServiceClass.getAnnotation(ApiInfo.class);
System.out.println("--- 类注解信息 ---");
System.out.println("API名称: " + classAnnotation.name());
System.out.println("API版本: " + classAnnotation.version());
System.out.println("是否启用: " + classAnnotation.enabled());
} else {
System.out.println("UserService 类没有 @ApiInfo 注解。");
}
System.out.println("\n--- 方法注解信息 ---");
// 检查并读取方法级别的注解
Method[] methods = userServiceClass.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(ApiInfo.class)) {
ApiInfo methodAnnotation = method.getAnnotation(ApiInfo.class);
System.out.println("方法名: " + method.getName());
System.out.println(" API名称: " + methodAnnotation.name());
System.out.println(" API版本: " + methodAnnotation.version());
System.out.println(" 是否启用: " + methodAnnotation.enabled());
}
}
}
}
4. 运行结果
执行 AnnotationReader 类的 main 方法,将输出以下内容:
--- 类注解信息 ---
API名称: UserService
API版本: v2
是否启用: true
--- 方法注解信息 ---
方法名: getUserDetails
API名称: getUserDetails
API版本: 1.0
是否启用: true