Java 注解介绍

注解(Annotation)是 Java 5 引入的一种新特性,它允许在代码中嵌入元数据(metadata),即描述数据的数据。注解提供了一种不修改代码逻辑但能够影响编译过程、代码执行或工具生成的机制。注解通常用于提供附加信息,编译器或运行时可以根据这些信息进行处理。

1. 注解的基本概念

注解本身不直接影响程序的执行,它们主要用来提供额外的信息,这些信息可以在编译时、类加载时或运行时进行处理。常见的注解包括 @Override@Deprecated@SuppressWarnings 等。

注解的基本语法:

// 单行注解
@AnnotationName
public class MyClass {
    // 类定义
}
  • 注解的声明以 @ 开头,后面跟着注解的名称。
  • 注解可以应用于类、方法、字段、参数、局部变量等位置。

2. 注解的类型

2.1 内置注解

Java 提供了一些内置注解,常见的包括:

  • @Override:表示方法重写,编译器会检查是否正确重写了父类方法。
  • @Deprecated:标记某个方法或类已不再推荐使用。
  • @SuppressWarnings:抑制特定的编译器警告。

2.2 自定义注解

Java 允许用户创建自定义注解。自定义注解的语法如下:

// 定义一个简单的注解
public @interface MyAnnotation {
    String value() default "default";  // 默认值为 "default"
}
  • @interface 用来定义一个注解类型。
  • 注解可以包含方法,这些方法在使用时会提供具体值。如果没有提供,注解的方法会使用默认值。

3. 注解的应用

注解可以用于多种目的,最常见的是:

  • 标记:为类、方法、字段等提供额外信息,方便工具或框架处理。
  • 编译时检查:通过注解帮助编译器进行代码检查,增强类型安全。
  • 运行时处理:注解信息可以通过反射获取,并在运行时执行相应操作。

3.1 使用内置注解

@Override 示例
class Animal {
    public void speak() {
        System.out.println("Animal speaks");
    }
}

class Dog extends Animal {
    @Override
    public void speak() {
        System.out.println("Dog barks");
    }
}

public class OverrideExample {
    public static void main(String[] args) {
        Animal myDog = new Dog();
        myDog.speak();  // 输出: Dog barks
    }
}
  • @Override 注解用于标识 Dog 类中的 speak() 方法是重写了父类 Animal 的方法。如果方法签名不匹配,编译器会提示错误。
@Deprecated 示例
class LegacyClass {
    @Deprecated
    public void oldMethod() {
        System.out.println("This method is deprecated");
    }
}

public class DeprecatedExample {
    public static void main(String[] args) {
        LegacyClass legacy = new LegacyClass();
        legacy.oldMethod();  // 编译器会提示警告: 使用了已弃用的方法
    }
}
  • @Deprecated 注解标识该方法已不推荐使用,编译时会发出警告。
@SuppressWarnings 示例
public class SuppressWarningsExample {
    @SuppressWarnings("unchecked")
    public void uncheckedWarningMethod() {
        // Suppresses unchecked warning
        List rawList = new ArrayList();
        rawList.add("Hello");
    }
}
  • @SuppressWarnings("unchecked") 注解用于抑制编译器发出的警告。

3.2 自定义注解的使用

定义自定义注解
public @interface MyAnnotation {
    String description() default "No description";  // 默认描述
    int version() default 1;                        // 默认版本
}
在代码中使用自定义注解
@MyAnnotation(description = "This is a custom annotation", version = 2)
public class CustomAnnotationExample {

    @MyAnnotation(description = "Method annotation", version = 1)
    public void myMethod() {
        System.out.println("This is a method with custom annotation");
    }
}
  • @MyAnnotation 是一个自定义注解,它可以应用于类或方法。
  • descriptionversion 是注解的元素,表示注解的属性,可以在使用时指定。
获取注解信息(反射)

在运行时,注解可以通过反射获取,并进行相关处理。例如,可以通过反射获取类或方法的注解,并基于注解的值执行某些操作。

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class AnnotationReflectionExample {
    public static void main(String[] args) throws Exception {
        Class<?> cls = CustomAnnotationExample.class;
        
        // 获取类的注解
        MyAnnotation classAnnotation = cls.getAnnotation(MyAnnotation.class);
        if (classAnnotation != null) {
            System.out.println("Class Description: " + classAnnotation.description());
            System.out.println("Class Version: " + classAnnotation.version());
        }
        
        // 获取方法的注解
        Method method = cls.getMethod("myMethod");
        MyAnnotation methodAnnotation = method.getAnnotation(MyAnnotation.class);
        if (methodAnnotation != null) {
            System.out.println("Method Description: " + methodAnnotation.description());
            System.out.println("Method Version: " + methodAnnotation.version());
        }
    }
}

输出:

Class Description: This is a custom annotation
Class Version: 2
Method Description: Method annotation
Method Version: 1
  • 通过 Class.getAnnotation()Method.getAnnotation() 方法可以获取类和方法上的注解信息。

4. 注解的生命周期

注解的生命周期分为以下几种:

  1. 编译时注解:注解只在编译阶段存在,编译器会进行检查。
  2. 类加载时注解:注解在编译后存在于字节码中,类加载时可以被读取。
  3. 运行时注解:注解在运行时通过反射读取,程序可以根据注解进行相应的逻辑处理。

注解的生命周期由 @Retention 注解指定。

@Retention 注解

  • @Retention(RetentionPolicy.SOURCE):注解只在源代码中存在,编译后被丢弃。
  • @Retention(RetentionPolicy.CLASS):注解在编译后的字节码中存在,但不包含在运行时。
  • @Retention(RetentionPolicy.RUNTIME):注解在运行时可用,可以通过反射读取。
Retention 示例:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface RuntimeAnnotation {
    String value();
}

class RuntimeAnnotationExample {
    @RuntimeAnnotation(value = "Example Annotation")
    public void annotatedMethod() {
        System.out.println("Method with runtime annotation");
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        Method method = RuntimeAnnotationExample.class.getMethod("annotatedMethod");
        if (method.isAnnotationPresent(RuntimeAnnotation.class)) {
            RuntimeAnnotation annotation = method.getAnnotation(RuntimeAnnotation.class);
            System.out.println("Annotation Value: " + annotation.value());
        }
    }
}

输出:

Annotation Value: Example Annotation
  • 通过 @Retention(RetentionPolicy.RUNTIME) 指定注解在运行时可用,允许使用反射来读取注解的值。

5. 注解与框架

在 Java 中,注解广泛应用于各种框架和库中,特别是在 SpringJUnit 等框架中。注解使得框架可以自动进行依赖注入、事务管理、单元测试等操作。

Spring 注解示例:

import org.springframework.stereotype.Component;

@Component
public class MyService {
    public void performService() {
        System.out.println("Service is performing an action");
    }
}
  • 在 Spring 框架中,@Component 注解标记类为一个 Spring 管理的组件,Spring 会自动创建并管理该对象。

JUnit 注解示例:

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class MyTest {

    @Test
    public void testAddition() {
        assertEquals(2, 1 + 1);
    }
}
  • JUnit 使用 @Test 注解标记测试方法,并根据注解来自动执行测试。

6. 总结

特性 内置注解自定义注解注解的作用
常见注解 @Override@Deprecated@SuppressWarnings 自定义注解 提供元数据,编译器和框架处理注解信息
用途 编译时检查,警告抑制,方法重写标识 提供附加元数据,代码注释 增加代码可读性和灵活性,动态处理注解信息
生命周期 SOURCECLASSRUNTIME 可指定生命周期 通过反射处理注解数据,编译或运行时处理

建议:

  • 在适当的场合使用注解,尤其是当需要向框架或工具提供额外的元数据时。
  • 理解不同注解生命周期的意义,确保在运行时能访问到注解的值(使用 @Retention(RetentionPolicy.RUNTIME))。
Java碎碎念 文章被收录于专栏

来一杯咖啡,聊聊Java的碎碎念呀

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务