当前位置:首页 > 技术 > 正文内容

Java 注解详解与自定义实践

访客 技术 2026年6月27日 1

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
    

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。