跳到主要内容

注解

简介

什么是注解

注解(Annotation)是Java 5引入的一种特殊的语法结构,用于在代码中添加元数据。它们可以被编译器、开发工具或运行时环境读取和处理,以提供额外的信息或指示。

Spring、JUnit、Hibernate等框架广泛使用注解来简化配置和增强代码的可读性。

为什么使用注解

在 Java 5 之前,元数据通常通过 JavaDoc 或 XML 配置文件来提供,这些方法有时不够灵活或易于维护。注解提供了一种更简洁和类型安全的方式来添加元数据。

注解基本知识

Java 内置注解

@Override

@Override 注解用于指示一个方法是重写父类的方法。它可以帮助编译器检查方法签名是否正确,并提高代码的可读性。

class Animal {
public void makeSound() {
System.out.println("动物发出声音");
}
}

class Dog extends Animal {
@Override // 明确表示这是重写父类的方法
public void makeSound() {
System.out.println("汪汪!");
}
/*
@Override
public void maekSound() { // 如果写错了方法名,编译器会立刻报错!
// error: method does not override or implement a method from a supertype
}
*/
}

@Deprecated

@Deprecated 注解用于标记一个类、方法或字段已过时,不建议使用。编译器会发出警告,提示开发者使用替代方案。

public class OldApi {
/**
* @deprecated 该方法已过时,请使用 newMethod() 代替。
*/
@Deprecated(since = "1.2", forRemoval = true)
public void oldMethod() {
System.out.println("这是一个旧的方法。");
}

public void newMethod() {
System.out.println("这是一个新的方法。");
}
}

// 在其他地方调用
OldApi api = new OldApi();
api.oldMethod(); // 编译器会在此处显示一条删除线,并给出警告
  • since:字符串值、指定自哪个版本开始该元素被标记为过时。
  • forRemoval:布尔值,如果为 true 表示该元素在未来版本中彻底删除。

@SuppressWarnings

@SuppressWarnings 注解用于抑制编译器的特定警告。它可以应用于类、方法或字段。

import java.util.ArrayList;
import java.util.List;

public class SuppressExample {
@SuppressWarnings("rawtypes") // 忽略使用原生类型的警告
public void useRawList() {
List list = new ArrayList(); // 如果没有 @SuppressWarnings,这里会有警告
list.add("Hello");
}

@SuppressWarnings({"unchecked", "rawtypes"}) // 可以同时忽略多种警告
public void useUncheckedList() {
List list = new ArrayList();
list.add("Hello");
List<String> strList = (List<String>) list; // "unchecked" 警告
}
}

元注解

元注解是用于注解其他注解的注解。

@Retention

@Retention 注解用于指定注解的保留策略,即注解的生命周期。它的值是一个 RetentionPolicy 枚举。

  • RetentionPolicy.SOURCE:注解只在源代码中存在,编译后会被丢弃。例如 Lombok 的注解。
  • RetentionPolicy.CLASS:注解在编译时存在,但在运行时不可用。
  • RetentionPolicy.RUNTIME:注解在运行时可用,可以通过反射来获取和使用。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME) // 确保注解在运行时可用
public @interface MyRuntimeAnnotation {
}

@Target

@Target 注解用于指定注解可以应用于哪些 Java 元素(类、方法、字段等)。它的值是一个 ElementType 枚举。

  • ElementType.TYPE:注解可以应用于类、接口或枚举。
  • ElementType.FIELD:注解可以应用于字段。
  • ElementType.METHOD:注解可以应用于方法。
  • ElementType.PARAMETER:注解可以应用于方法参数。
  • ElementType.CONSTRUCTOR:注解可以应用于构造函数。
  • ElementType.LOCAL_VARIABLE:注解可以应用于局部变量。
  • ElementType.ANNOTATION_TYPE:注解可以应用于其他注解。
  • ElementType.PACKAGE:注解可以应用于包。
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.FIELD}) // 这个注解只能用于方法和字段
public @interface MyAnnotation {
}

@Documented

@Documented 注解用于指示注解应该包含在 Javadoc 中。它通常与其他元注解一起使用。

@Inherited

@Inherited 注解用于指示一个注解可以被子类继承。只有类级别的注解可以使用此元注解。

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyInheritedAnnotation {
String value() default "default value";
}
@MyInheritedAnnotation("parent class")
class ParentClass {
}
@MyInheritedAnnotation("child class")
class ChildClass extends ParentClass {
}

自定义注解

自定义注解可以帮助开发者定义特定的元数据,用于实现特定的功能。

创建自定义注解

创建自定义注解需要使用 @interface 关键字,并可以结合元注解来定义其行为。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

使用自定义注解

在代码中进行使用。

@MyAnnotation(value = "测试注解", count = 3)
public class TestClass {
@MyAnnotation(value = "方法注解")
public void testMethod() {
System.out.println("执行测试方法");
}
}

读取自定义注解

可以使用反射来读取自定义注解的信息。

import java.lang.reflect.Method;

public class AnnotationProcessor {
public static void main(String[] args) throws Exception {
Class<TestClass> clazz = TestClass.class;

// 解析类上的注解
if (clazz.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class);
System.out.println("类注解值: " + annotation.value());
}

// 解析方法上的注解
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
System.out.println("方法注解值: " + annotation.value());
}
}
}
}

注解本身不具备逻辑功能,需要结合代码进行综合应用。