深入理解 @Target 和 @Retention 注解

深入理解 @Target 和 @Retention 注解

在 Java 中,注解是一种元数据,为代码提供额外信息。在自定义注解时,@Target@Retention 是两个非常重要的元注解,它们用于控制注解的适用范围和生命周期。本文将详细介绍这两个注解的作用,尤其是在下面这个示例中的使用场景:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "";
}

1. 什么是 @Target?

@Target 注解指定了自定义注解可以应用到哪些代码元素。其取值来自枚举 ElementType,常见值包括:

  • ElementType.TYPE:类、接口(包括注解类型)或枚举。
  • ElementType.METHOD:方法。
  • ElementType.FIELD:字段或枚举常量。
  • ElementType.PARAMETER:方法参数。
  • ElementType.CONSTRUCTOR:构造器。
  • ElementType.LOCAL_VARIABLE:局部变量。
  • ElementType.ANNOTATION_TYPE:其他注解。
  • ElementType.PACKAGE:包声明。
  • ElementType.MODULE:模块。

作用

@Target 限制了注解的使用范围,防止开发者误用注解。例如,如果一个注解仅适用于方法,将 @Target(ElementType.METHOD) 限制后,编译器会在其他位置(如类或字段)使用时报错。

示例

@Target(ElementType.METHOD)
public @interface LogExecution {
    String value() default "default message";
}

// 正确:用于方法
public class Test {
    @LogExecution("Log this method execution")
    public void execute() {
        System.out.println("Executing...");
    }

// 错误:用于类(编译器报错)
// @LogExecution
// public class TestClass { }

2. 什么是 @Retention?

@Retention 注解决定了自定义注解的生命周期(即注解信息会保留到代码的哪个阶段)。其取值来自枚举 RetentionPolicy,包括:

  • RetentionPolicy.SOURCE:注解只存在于源代码中,编译后会被丢弃。例如,@Override
  • RetentionPolicy.CLASS:注解在编译时被保留到 .class 文件中,但不会加载到 JVM 中。
  • RetentionPolicy.RUNTIME:注解不仅会保留到 .class 文件中,还会在运行时通过反射读取。

作用

通过 @Retention,开发者可以控制注解的存活范围:

  • 如果注解仅供编译器使用(如生成代码或验证规则),可选 SOURCE
  • 如果注解需要保留到运行时(如框架或库中通过反射解析),应选 RUNTIME

示例

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Monitor {
    String value() default "Monitor this method";
}

// 使用注解
public class Service {
    @Monitor("Performance monitoring")
    public void process() {
        System.out.println("Processing...");
    }

// 运行时通过反射读取注解
import java.lang.reflect.Method;

public class AnnotationProcessor {
    public static void main(String[] args) throws Exception {
        Method method = Service.class.getMethod("process");
        if (method.isAnnotationPresent(Monitor.class)) {
            Monitor monitor = method.getAnnotation(Monitor.class);
            System.out.println("Annotation value: " + monitor.value());
        }
    }
}

输出:

Annotation value: Performance monitoring

3. 综合示例:自定义注解的应用

假设我们想为某些关键方法添加日志记录功能,可以结合 @Target@Retention 自定义注解,并在运行时通过反射读取这些注解。

自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecution {
    String value() default "Default log message";
}

应用注解

public class BusinessService {
    @LogExecution("Log execution of method: calculate")
    public void calculate() {
        System.out.println("Calculating...");
    }

    @LogExecution("Log execution of method: report")
    public void report() {
        System.out.println("Generating report...");
    }
}

注解处理器

import java.lang.reflect.Method;

public class LogProcessor {
    public static void main(String[] args) throws Exception {
        BusinessService service = new BusinessService();

        for (Method method : BusinessService.class.getDeclaredMethods()) {
            if (method.isAnnotationPresent(LogExecution.class)) {
                LogExecution logExecution = method.getAnnotation(LogExecution.class);
                System.out.println("Executing: " + method.getName());
                System.out.println("Log: " + logExecution.value());

                // 执行方法
                method.invoke(service);
            }
        }
    }
}

输出:

Executing: calculate
Log: Log execution of method: calculate
Calculating...
Executing: report
Log: Log execution of method: report
Generating report...

4. 总结

  • @Target:限制注解的使用范围,确保注解只在适合的位置使用。
  • @Retention:控制注解的生命周期,决定注解是否能在运行时被反射读取。

在实际开发中,@Target@Retention 是自定义注解必不可少的组成部分。通过合理设置这两个元注解,可以确保注解设计更安全、更高效,同时为框架开发和工具集成提供了灵活性。

posted @   佳楠的个人Log  阅读(449)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示