【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);
}
相关推荐
2301_7807896615 小时前
跨平台适配!SDK 游戏盾兼容全终端游戏场景
java·网络·ddos
学长毕设16 小时前
基于springboot的食品仓库管理系统
java·spring boot·后端
步行cgn17 小时前
FormHttpMessageConverter 详解:Spring MVC 中表单数据的读写转换器
java·spring·mvc
龙亘川17 小时前
构建城市公共安全数字底座:亘川智城智慧安防系统全维度解读
java·大数据·开发语言·人工智能·信息可视化
金銀銅鐵17 小时前
[Java] 用 CLI 展示 EnumMap 增删键值对时的内部变化
java·源码·ai编程
秋天的怀念_David17 小时前
第二十二夜 · 数字迷雾
java·程序人生·算法
Raas10017 小时前
AI网关部署方案?从部署到上线全流程
java·开发语言·人工智能·gateway·ai网关·企业级ai网关·企业级ai产品
niucloud-admin18 小时前
NIUCLOUD PHP SAAS上门家政使用文档:城市管理
java·前端·php
霸道流氓气质18 小时前
智能客服组件:分层意图识别、RAG Advisor 与人工转接状态机的 Vue3 + Spring AI 生产级实战
java·人工智能·spring
captain37619 小时前
MyBatis操作数据库(入门2)
java·数据库·spring boot·后端·spring·mybatis