【Java】注解

注解概述

什么是注解

注解(Annotation)是一种用于为类、方法、字段、参数等添加结构化元数据(Metadata)的机制。它的主要作用不是直接影响代码的逻辑,而是提供信息给编译器、工具或运行时框架,用于辅助处理。

注解的基本特点:

  • 不影响代码本身的业务逻辑;
  • @ 开头,例如:@Override
  • 可被编译器读取;
  • 可在运行时通过反射读取(取决于注解的保留策略)。

注解和注释

对比项 注解(Annotation) 注释(Comment)
目的 向编译器、工具或框架传递"结构化信息" 给开发者阅读的文本说明
影响编译或运行 可能会影响(如检查、生成代码) 不影响
是否被程序读取 可通过反射等方式读取 运行时不可读取
语法形式 @AnnotationName ///* *//** */
用途 配置、约束、框架驱动 文档说明、备注

一句话:

注解是机器看的,注释是人看的。

注解的重要性

① 提升代码可读性和可靠性

例如:

  • @Override 会提示编译器检查方法是否真正重写了父类方法。
  • @Deprecated 标识一个方法已过时,提示开发者谨慎使用。

② 支持编译器检查与代码生成

如:

  • Lombok 使用注解生成 Getter/Setter 等代码;
  • MapStruct 使用注解生成对象映射代码;
  • JUnit 测试使用 @Test 标记测试方法。

③ 是许多框架运作的基础

例如:

  • Spring:@Autowired@Component@Configuration 等实现依赖注入和配置;
  • JPA:@Entity@Table@Column 等用于 ORM 映射;
  • Swagger:@Api@ApiModelProperty 等用于接口文档生成。

这些框架大量使用注解来描述:

  • 组件、配置
  • 依赖关系
  • 映射关系
  • 权限控制
  • 生命周期行为

可以说:

现代 Java 开发已经离不开注解。注解使框架实现"约定优于配置"成为可能。

④ 方便工具链处理

注解可用于:

  • 编译期校验(如 @Nonnull
  • 文档生成(如 @DocRoot
  • 编译增强(如 APT)

常用基本注解

文档相关注解

java 复制代码
@author                 说明类、接口或方法的作者。
/**
 * 工具类示例
 * @author Zhang
 */
public class Utils {}

@version                 指定版本号。
/**
 * @version 1.0.0
 */
    
@since                   说明该元素从哪个版本开始提供。
/**
 * @since 1.5
 */

@param                   对方法中某参数的说明,如果没有参数就不能写
@return                  对方法返回值的说明,如果方法的返回值类型是void就不能写
/**
* 求圆面积的方法
* @param radius double 半径值
* @return double 圆的面积
*/
public static double getArea(double radius) {
	return Math.PI * radius * radius;
}
@exception               对方法可能抛出的异常进行说明 ,如果方法没有用throws显式抛出的异常就不能写
    
@deprecated              表示元素已过时,可结合 @Deprecated 注解一起用。
/**
 * @deprecated 请改用 newMethod()
 */
@Deprecated
public void oldMethod() {}

{@link ClassName}        插入一个到指定类、方法的链接。
/**
 * 处理对象,详情见 {@link java.util.List}
 */

最基本的 3 个编译时检查注解(JDK 内置)

1、@Override

表示该方法必须覆盖父类的方法。如果方法签名不匹配,编译器会报错。

java 复制代码
class Parent {
    void speak() {}
}

class Child extends Parent {
    @Override
    void speak() {
        System.out.println("Child speaking");
    }
}

2、@Deprecated

标记方法或类为过时,不建议使用。使用时 IDE 会给出警告。

java 复制代码
@Deprecated
public void oldApi() {
    System.out.println("old");
}

public void newApi() {
    System.out.println("new");
}

3、@SuppressWarnings

抑制编译器警告,如原生类型使用、未使用变量等。

常用参数:

  • "unchecked":忽略泛型未检查警告
  • "deprecation":忽略访问过时 API 的警告
  • "rawtypes":忽略原生类型使用警告
java 复制代码
@SuppressWarnings({"unchecked", "deprecation"})
public void test() {
    List list = new ArrayList(); // unchecked
    oldApi();                    // deprecation
}

元注解

元注解(Meta-Annotation) 是指用于修饰 注解本身 的注解。它们用于描述一个注解的行为规则,包括:注解可以用在什么位置、在什么阶段有效、是否会被继承、是否包含在 Javadoc 中等。

1、@Retention ------ 指定注解的生命周期

用于说明该注解在程序运行的哪个阶段可用。

RetentionPolicy 枚举:

可选值 描述
SOURCE 只在源代码中存在,编译后丢弃。例如 @Override
CLASS(默认) 编译后保留在 class 文件中,但运行时不可见
RUNTIME 运行时仍然存在,可通过反射读取
java 复制代码
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}

2、@Target ------ 指定注解可以应用的程序元素位置

限制注解可以用在哪些地方,否则会导致编译错误。

ElementType 可选范围:

  • TYPE(类、接口、枚举)
  • METHOD
  • FIELD
  • PARAMETER
  • CONSTRUCTOR
  • LOCAL_VARIABLE
  • ANNOTATION_TYPE
  • PACKAGE
  • TYPE_PARAMETER(Java 8+)
  • TYPE_USE(Java 8+)
java 复制代码
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface MyAnnotation {}

表示该注解只能用于方法和字段。

3、@Inherited ------ 指定注解是否可被子类继承

若一个注解被 @Inherited 修饰,则当它作用在类上时,子类将自动继承该注解。

注意:

@Inherited 只对类(class)有效,对方法、属性无效。

java 复制代码
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}

@MyAnnotation
class Parent {}

class Child extends Parent {}  // Child 也拥有 MyAnnotation

4、@Documented ------ 指定注解是否包含在 Javadoc 中

让使用了该注解的地方,在生成 Javadoc 时也能看到注解说明。

java 复制代码
@Documented
public @interface MyAnnotation {}

自定义注解

声明自定义注解

java 复制代码
[元注解]
[修饰符] @interface 注解名 {
    [成员列表]
}
  • Java 用 4 个元注解来声明自定义注解的行为;
  • 注解的成员在注解定义中以【无参数有返回值的抽象方法】的形式来声明,又称为配置参数。返回值类型只能是基本数据类型、String类型、Class类型、enum类型、Annotation类型、以上类型的一维数组。
  • 可以使用default关键字为抽象方法指定默认返回值。
  • 如果定义的注解含有抽象方法,那么使用时必须指定返回值,除非它有默认值。格式:方法名 = 返回值,如果只有一个抽象方法需要赋值,且方法名为value,使用时可以省略value=,所以如果注解只有一个抽象方法成员,建议使用方法名value

使用自定义注解

java 复制代码
public enum Priority { LOW, MEDIUM, HIGH; }

public @interface SubAnnotation {
    String value();
}
java 复制代码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyAnnotation {

    String author() default "anonymous";

    int revision() default 1;

    String[] tags() default {};

    Class<?> targetClass() default Object.class;

    // 枚举类型
    Priority level() default Priority.MEDIUM;

    // 注解类型成员
    SubAnnotation info() default @SubAnnotation("default");
}

用在类上

java 复制代码
@MyAnnotation(
    author = "Alice",
    revision = 2,
    tags = {"core", "annotation"},
    targetClass = String.class,
    level = Priority.HIGH,
    info = @SubAnnotation("sub-info")
)
public class Demo {
}

用在方法上

java 复制代码
public class Demo {
    @MyAnnotation(author = "Bob", revision = 3)
    public void test() {}
}

注解的读取

自定义注解必须配上注解的信息处理流程才有意义。

自定义注解只能使用反射的代码读取,所以注解必须使用 @Retention(RetentionPolicy.RUNTIME)

1、读取类上的注解

java 复制代码
Class<?> clazz = Demo.class;

if (clazz.isAnnotationPresent(MyAnnotation.class)) {
    MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class);
    System.out.println(annotation.author());
    System.out.println(annotation.revision());
}

2、读取方法上的注解

java 复制代码
Method method = Demo.class.getMethod("test");

if (method.isAnnotationPresent(MyAnnotation.class)) {
    MyAnnotation a = method.getAnnotation(MyAnnotation.class);
    System.out.println(a.author());
}

3、读取所有注解

java 复制代码
Annotation[] annotations = clazz.getAnnotations();
for (Annotation a : annotations) {
    System.out.println(a);
}
相关推荐
繁华似锦respect1 小时前
C++ 设计模式之工厂模式详细介绍
java·linux·c++·网络协议·设计模式
想要成为祖国的花朵1 小时前
基于多设计模式的抽奖系统__测试报告
java·selenium·测试工具·jmeter·设计模式·测试用例·安全性测试
v***5651 小时前
常见的 Spring 项目目录结构
java·后端·spring
超频化石鱼2 小时前
使用Postman访问siliconflow大模型接口
java·postman·ai编程
f***45322 小时前
SpringCloud篇(配置中心 - Nacos)
java·spring·spring cloud
b***66612 小时前
Spring Framework 中文官方文档
java·后端·spring
7***47712 小时前
【SQL】掌握SQL查询技巧:数据分组与排序
java·jvm·sql
好好研究2 小时前
MyBatis框架 - 逆向工程
java·数据库·mybatis
关于不上作者榜就原神启动那件事2 小时前
心跳机制详解
java·前端·servlet