Java注解

1. 概述、自定义注解

从JDK 5 开始,Java 增加了对元数据(MetaData)的支持,也就是 Annotation(即注解,也被翻译为注释)。本章所介绍的 Annotation,其实是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。通过使用注解, 程序开发人员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充的信息。代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或者进行部署。

举例: @Override、@Test等等,作用是:让其他程序根据注解信息来决定怎么执行该程序。注解可以使用在类上、构造器上、方法上、成员变量上、参数上等位置。

在这里插入图片描述

1.1 注意

Annotation 是一个接口,程序可以通过反射来获取指定程序元素的 Annotation 对象, 然后通过 Annotation 对象来取得注解里的元数据。读者需要注意本章中使用 Annotation 的地方,有的 Annotation 指的是 java.lang.Annotation 接口,有的指的是注解本身。

Annotation 能被用来为程序元素(类、方法、成员变量等)设置元数据。值得指出的是,Annotation 不影响程序代码的执行,无论增加、删除 Annotation,代码都始终如一地执行。如果希望让程序中的 Annotation 在运行时起一定的作用,只有通过某种配套的工具对 Annotation 中的信息进行访问和处理, 访问和处理 Annotation 的工具统称 APT (Annotation Processing Tool)。

2. 自定义注解

自定义注解的格式
在这里插入图片描述

在这里插入图片描述

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RecordOperate {
	String desc() default "";

	Class<? extends Convert> convert();
}
package annotation;

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

// 定义注解
@Retention(RetentionPolicy.RUNTIME)  // 指定注解的保留策略
@Target(ElementType.METHOD)          // 指定注解的使用目标
public @interface MyAnnotation {
    String value() default "default value"; // 特殊属性

    int number() default 0;
}
public class MyClass {

    @MyAnnotation(value = "test value", number = 10)
    public void myMethod() {
        System.out.println("This is a method with custom annotation.");
    }
}
package annotation;

import java.lang.reflect.Method;

public class AnnotationProcessor {
    public static void main(String[] args) {
        try {
            // 获取MyClass的Class对象
            Class<MyClass> myClassClass = MyClass.class;

            // 获取所有方法
            Method[] methods = myClassClass.getDeclaredMethods();

            // 遍历所有方法
            for (Method method : methods) {
                // 检查方法是否有MyAnnotation注解
                if (method.isAnnotationPresent(MyAnnotation.class)) {
                    // 获取注解
                    MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);

                    // 打印注解的值
                    System.out.println("Method: " + method.getName());
                    System.out.println("Value: " + annotation.value());
                    System.out.println("Number: " + annotation.number());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.1 注解的原理

在这里插入图片描述

3. JDK中的元Annotaion

JDK除了在 java.lang 下提供了5个基本的 Annotation 之外,还在 java.lang.annotation 包下提供了6 个 Meta Annotation(元 Annotation),其中有5个元 Annotation 都用于修饰其他的 Annotation 定义。其中@Repeatable 专门用于定义 Java 8新增的重复注解。

3.1 @Retention

@Retention 只能用于修饰 Annotation 定义,用于指定被修饰的 Annotation可以保留多长时间, @Retention 包含一个 RetentionPolicy 类型的 value 成员变量,所以使用@Retention 时必须为该 value 成员变量指定值。

value 成员变量的值只能是如下三个。

  • RetentionPolicy.CLASS:编译器将把 Annotation记录在class文件中。当运行Java程序时,JVM 不可获取 Annotation信息。这是默认值。
  • RetentionPolicy.RUNTIME:编译器将把 Annotation 记录在 class 文件中。当运行 Java 程序时,JVM也可获取Annotation信息,程序可以通过反射获取该 Annotation 信息。
  • RetentionPolicy.SOURCE: Annotation 只保留在源代码中,编译器直接丢弃这种 Annotation。

如果需要通过反射获取注解信息,就需要使用 value 属性值为RetentionPolicy.RUNTIME@Retention。使用@RetentionAnnotation可采用如下代码为 value 指定值。

//定义下面的 Testable Annotation 保留到运行时 
@Retention (value = RetentionPolicy.RUNTIME) 
public @interface Testablel{}

3.2 @Target

@Target 也只能修饰一个Annotation定义,它用于指定被修饰的 Annotation 能用于修饰哪些程序单元。@Target 元 Annotation 也包含一个名为 value 的成员变量,该成员变量的值只能是如下几个。

  • ElementType.ANNOTATION_TYPE:指定该策略的 Amnotation 只能修饰 Amotation。
  • ElementType.CONSTRUCTOR:指定该策略的 Annotation 只能修饰构造器。
  • ElementType.FIELD:指定该策略的 Annotation 只能修饰成员变量。
  • ElementType.LOCAL_VARIABLE:指定该策略的 Annotation 只能修饰局部变量。
  • ElementType.METHOD:指定该策略的 Annotation 只能修饰方法定义。
  • ElementType.PACKAGE:指定该策略的 Annotation 只能修饰包定义。
  • ElementType.PARAMETER:指定该策略的 Annotation 可以修饰参数。
  • ElementType.TYPE:指定该策略的 Annotation 可以修饰类、接口(包括注解类型)或枚举定义。

在这里插入图片描述

与使用 @Retention类似的是,使用@Target 也可以直接在括号里指定 value 值,而无须使用 name-value 的形式。如下代码指定@ActionListenerFor Annotation 只能修饰成员变量。
在这里插入图片描述
在这里插入图片描述

3.3 使用@Documented

@Documented 用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档,如果定义 Annotation 类时使用了@Documented修饰,则所有使用该 Annotation 修饰的程序元素的 API 文档中将会包含该 Annotation 说明。

下面代码定义了一个 Testable Annotation,程序使用@Documented 来修饰@Testable Annotation 定义, 所以该 Annotation 将被 javadoc 工具所提取。

在这里插入图片描述

上面代码中的粗体字代码指定了 javadoe 工具生成的 API文档将提取@Testable 的使用信息。
下面代码定义了一个 MyTest 类,该类中的 info()方法使用了@Testable 修饰。

在这里插入图片描述

3.4 使用@Inherited

@Inherited 元 Annotation 指定被它修饰的 Annotation 将具有继承性——如果某个类使用了@Xxx注解(定义该 Annotation 时使用了@Inherited 修饰)修饰,则其子类将自动被@Xxx 修饰。

或者说:@Inherited 是 Java 中的一个注解,用于指示某个注解类型可以被自动继承。如果一个类使用了带有 @Inherited 注解的注解,那么它的子类将会自动继承该注解。这个注解仅适用于类(Class),不适用于方法、字段、参数等其他元素。

@Inherited 注解的使用示例

  • @Inherited 是一个元注解(用于注解其他注解)。
  • 它位于 java.lang.annotation 包中。
  • 它只能用于注解类型上,不能用于其他元素(如方法、字段等)。
  • 当带有 @Inherited 注解的注解被使用在一个类上时,该注解将会被其子类继承。

3.4.1 @Inherited 注解的使用示例

下面是一个简单的例子,演示如何使用 @Inherited 注解。

  1. 创建一个带有 @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 "Inherited Annotation";
}

  1. 使用 @MyInheritedAnnotation 注解父类
@MyInheritedAnnotation
public class ParentClass {
    // Parent class code
}
  1. 创建一个继承父类的子类
public class ChildClass extends ParentClass {
    // Child class code
}
  1. 测试继承效果
import java.lang.annotation.Annotation;

public class InheritedAnnotationDemo {
    public static void main(String[] args) {
        // 获取父类上的注解
        Annotation[] parentAnnotations = ParentClass.class.getAnnotations();
        System.out.println("Annotations on ParentClass:");
        for (Annotation annotation : parentAnnotations) {
            System.out.println(annotation);
        }

        // 获取子类上的注解
        Annotation[] childAnnotations = ChildClass.class.getAnnotations();
        System.out.println("\nAnnotations on ChildClass:");
        for (Annotation annotation : childAnnotations) {
            System.out.println(annotation);
        }
    }
}
  1. 运行结果
Annotations on ParentClass:
@MyInheritedAnnotation(value=Inherited Annotation)

Annotations on ChildClass:
@MyInheritedAnnotation(value=Inherited Annotation)

从上述结果可以看出,尽管我们只在 ParentClass 上使用了 @MyInheritedAnnotation 注解,但 ChildClass 也自动继承了该注解。

  • 34
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

boy快快长大

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

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

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

打赏作者

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

抵扣说明:

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

余额充值