Java—注解机制详解

概念

注解是类的组成部分,可以为类携带额外的信息,提供一种安全的注释标记机制,用于将任何信息或元数据与程序元素(如类、方法、成员变量等)关联。

  • 注解是供编译器或JVM使用的,编译器或JVM可以根据注解执行相应的功能。
  • 注解类似于修饰符,适用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。
  • 父类中的注解不能被子类继承。

注解的作用

  • 标记:为类、方法或变量添加元数据,便于工具或框架识别。
  • 框架支持:许多框架利用注解和反射来实现功能,这是框架的底层基础技术。
  • 编译时检查:如 @Override 用于方法重写约束,@FunctionalInterface 用于函数式接口约束。

注解格式

定义格式:自定义注解用 @interface 关键字,注解默认可以标记很多地方

修饰符 @interface 注解名{
     // 注解属性
}

使用注解的格式:@注解名

// 自定义注解
@interface MyAnnotation {
    String value();
}

// 使用注解
@MyAnnotation(value = "示例注解")
public class Example {
    @Override
    public String toString() {
        return "这是一个示例类";
    }
}

常用注解

@Override:检查方法是否正确重写父类方法。
@Deprecated:标记某个方法或类为过时,不建议使用。
@SuppressWarnings:抑制特定的编译器警告。
@FunctionalInterface:指示接口为函数式接口。

注解属性

普通属性

注解可以包含属性,属性名必须带 ()。在使用注解时,属性必须赋值,除非属性定义了默认值。

属性的格式:

  • 格式 1:数据类型 属性名()
  • 格式 2:数据类型 属性名() default 默认值

适用的数据类型:

  • 八种基本数据类型:int、short、long、double、byte、char、boolean、float
  • String
  • Class
  • 以上类型的数组形式也被支持

特殊属性

注解中有一个特殊属性名称:value

  • 如果注解只有一个 value 属性,可以在使用时省略 value 名称。
  • 如果有多个属性且没有默认值,则 value 属性不能省略。

示例

// 自定义注解
@interface MyAnnotation {
    String name(); // 必须提供
    int age() default 18; // 默认值为18
    String[] tags() default {}; // 默认值为空数组
    String value(); // 特殊属性
}

// 使用注解
@MyAnnotation(name = "示例", value = "测试")
public class Example {
    // ...
}

// 省略 value 属性
@MyAnnotation(name = "示例", value = "测试")
public class AnotherExample {
    // ...
}

在以上示例中,MyAnnotation 定义了多个属性,包括一个特殊属性 value。使用时可以选择性地省略 value。

元注解概述

元注解是 Java 中用于注解自定义注解的注解,主要由 Sun 公司提供。它们可以控制自定义注解的应用范围和行为。元注解包括以下四种:

@Target

用于指定自定义注解可以应用于哪些 Java 元素。其默认值为任何元素。可用值定义在 ElementType 类中,主要包括:

  • ElementType.CONSTRUCTOR:用于描述构造器。
  • ElementType.FIELD:用于描述成员变量、对象、属性(包括 enum 实例)。
  • ElementType.LOCAL_VARIABLE:用于描述局部变量。
  • ElementType.METHOD:用于描述方法。
  • ElementType.PACKAGE:用于描述包。
  • ElementType.PARAMETER:用于描述方法参数。
  • ElementType.TYPE:用于描述类、接口(包括注解类型)或 enum 声明。

@Retention

定义注解的生命周期,声明注解的作用范围。可用值定义在 RetentionPolicy 枚举类中:

  • RetentionPolicy.SOURCE:在编译阶段丢弃,这些注解在编译结束后不再存在于字节码中,仅用于源码阶段,如 @Override 和 @SuppressWarnings。
  • RetentionPolicy.CLASS:在类加载时丢弃,字节码文件中存在,但在运行时不存在。这是默认值。
  • RetentionPolicy.RUNTIME:在运行期保留该注解,因此可以使用反射机制读取注解信息。自定义注解通常使用这种方式。

@Inherited

  • 表示修饰的自定义注解可以被子类继承。仅适用于类类型的注解。

@Documented

  • 指示该注解是否应包含在 Java 文档中。使用此注解标记的自定义注解在生成的文档中会包含其元信息。

示例

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

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyCustomAnnotation {
    String value() default "default";
}

注解解析概述

在 Java 开发中,注解解析是理解和利用注解的关键。通过反射机制,可以动态地获取类、方法、字段等元素上的注解信息。以下是与注解解析相关的核心接口和类的概述。

相关接口与类

  • Annotation:所有注解的父类,所有自定义注解都继承自这个接口。
  • AnnotatedElement:定义了与注解解析相关的方法,提供了一系列获取注解的功能。
  • Class、Method、Field、Constructor:这些类实现了 AnnotatedElement 接口,因此可以通过它们获取注解信息。

Class 类 API

  • Annotation[] getDeclaredAnnotations():获取当前对象上声明的所有注解,返回一个注解数组。
  • T getDeclaredAnnotation(Class<T> annotationClass):根据注解类型获取对应的注解对象,仅返回当前对象上声明的注解。
  • T getAnnotation(Class<T> annotationClass):获取当前对象及其父类上声明的指定类型的注解。
  • boolean isAnnotationPresent(Class<Annotation> annotationClass):判断当前对象是否使用了指定类型的注解。
  • boolean isAnnotation():判断当前 Class 对象是否表示注解类型。

注解的原理

注解本质上是特殊接口,继承了 Annotation 接口。在运行时,Java 为每个注解生成一个动态代理类。当通过反射获取注解时,返回的是动态代理对象(例如 $Proxy1),通过这个代理对象调用注解的方法时,实际上会回调 AnnotationInvocationHandler 的 invoke 方法。

这个方法从 memberValues 这个 Map 中获取注解属性的值,而 memberValues 的数据来源于 Java 常量池。

注解数据解析原理

注解的解析通常遵循以下步骤:

  1. 确定注解的作用对象(类、方法等)。
  2. 获取对应的 Class 对象。
  3. 使用上述 API 方法从 Class 对象中获取注解信息。

示例

package com.example;

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

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

@MyAnnotation(value = "Example Class")
class ExampleClass {
}

public class AnnotationParser {
    public static void main(String[] args) {
        Class<ExampleClass> exampleClass = ExampleClass.class;

        // 检查是否存在注解
        if (exampleClass.isAnnotationPresent(MyAnnotation.class)) {
            // 获取注解
            MyAnnotation annotation = exampleClass.getAnnotation(MyAnnotation.class);
            System.out.println("注释值: " + annotation.value());
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Onlooker﹒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值