Java 注解详解与自定义注解

什么是注解(Annotation)

注解是 Java 5 引入的一种元数据形式,它提供了一种向代码添加结构化元数据的方式。注解本身不影响代码逻辑,但可以被编译器、开发工具或运行时环境读取并做相应处理。

注解的主要用途

  1. 编译器信息:如 @Override@Deprecated@SuppressWarnings
  2. 代码分析:静态分析工具使用
  3. 运行时处理:框架如 Spring、Hibernate 使用
  4. 文档生成:如 @see@author

Java 内置常用注解

  • @Override:标记方法重写
  • @Deprecated:标记过时元素
  • @SuppressWarnings:抑制编译器警告
  • @FunctionalInterface:标记函数式接口
  • @SafeVarargs:抑制堆污染警告

如何自定义注解

1. 定义注解

使用 @interface 关键字定义注解:

// 简单的标记注解
public @interface MyAnnotation {
}

// 带属性的注解
public @interface Author {
    String name();          // 属性,类似方法声明
    String date();          // 另一个属性
    int version() default 1; // 带默认值的属性
}

2. 元注解(Meta-annotations)

用于注解其他注解的注解,Java 提供了 5 种元注解:

@Target(ElementType.METHOD)     // 指定注解可以应用的目标(方法、类等)
@Retention(RetentionPolicy.RUNTIME) // 指定注解保留策略(源码、类文件、运行时)
@Documented                     // 注解包含在Javadoc中
@Inherited                      // 注解可被子类继承
@Repeatable(MyAnnotations.class) // 注解可重复使用(Java 8+)
2.1 @Target 指定使用范围

ElementType 枚举值:

  • TYPE:类、接口、枚举
  • FIELD:字段
  • METHOD:方法
  • PARAMETER:参数
  • CONSTRUCTOR:构造器
  • LOCAL_VARIABLE:局部变量
  • ANNOTATION_TYPE:注解类型
  • PACKAGE:包
  • TYPE_PARAMETER:类型参数(Java 8+)
  • TYPE_USE:类型使用(Java 8+)
2.2 @Retention 指定保留策略

RetentionPolicy 枚举值:

  • SOURCE:仅源码保留,编译器丢弃
  • CLASS:类文件中保留,JVM不加载(默认)
  • RUNTIME:运行时保留,可通过反射读取

3. 注解属性类型

注解属性(看起来像方法)支持的类型:

  • 基本类型(int, float, boolean 等)
  • String
  • Class
  • 枚举
  • 注解
  • 以上类型的数组

4. 使用自定义注解

@Author(name = "张三", date = "2023-01-01", version = 2)
public class MyClass {
    
    @MyAnnotation
    public void myMethod() {
        // ...
    }
}

5. 处理注解(运行时)

通过反射读取运行时保留的注解:

Class<?> clazz = MyClass.class;

// 获取类上的注解
Author author = clazz.getAnnotation(Author.class);
if (author != null) {
    System.out.println("作者: " + author.name());
    System.out.println("日期: " + author.date());
    System.out.println("版本: " + author.version());
}

// 获取方法上的注解
Method method = clazz.getMethod("myMethod");
if (method.isAnnotationPresent(MyAnnotation.class)) {
    System.out.println("方法使用了MyAnnotation注解");
}

完整自定义注解示例

1. 定义注解

import java.lang.annotation.*;

// 定义注解可用于方法和类
@Target({ElementType.METHOD, ElementType.TYPE})
// 注解在运行时保留
@Retention(RetentionPolicy.RUNTIME)
// 包含在Javadoc中
@Documented
public @interface CustomAnnotation {
    String value() default "默认值";  // 特殊属性value,使用时可以省略属性名
    String description();
    String[] tags() default {};     // 数组属性
    boolean enabled() default true;
}

2. 使用注解

@CustomAnnotation(description = "这是一个测试类", tags = {"test", "demo"})
public class TestClass {
    
    @CustomAnnotation(value = "特殊值", description = "测试方法")
    public void testMethod() {
        // ...
    }
}

3. 处理注解

public class AnnotationProcessor {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = TestClass.class;
        
        // 处理类上的注解
        processClassAnnotation(clazz);
        
        // 处理方法上的注解
        Method method = clazz.getMethod("testMethod");
        processMethodAnnotation(method);
    }
    
    private static void processClassAnnotation(Class<?> clazz) {
        if (clazz.isAnnotationPresent(CustomAnnotation.class)) {
            CustomAnnotation annotation = clazz.getAnnotation(CustomAnnotation.class);
            System.out.println("类注解信息:");
            System.out.println("value: " + annotation.value());
            System.out.println("description: " + annotation.description());
            System.out.println("tags: " + String.join(", ", annotation.tags()));
            System.out.println("enabled: " + annotation.enabled());
        }
    }
    
    private static void processMethodAnnotation(Method method) {
        if (method.isAnnotationPresent(CustomAnnotation.class)) {
            CustomAnnotation annotation = method.getAnnotation(CustomAnnotation.class);
            System.out.println("\n方法注解信息:");
            System.out.println("value: " + annotation.value());
            System.out.println("description: " + annotation.description());
        }
    }
}

你可能感兴趣的:(java,java,开发语言)