自定义注解详细介绍转载

原创
小哥 3年前 (2022-10-27) 阅读数 48 #大杂烩

1 注解的概念
1.1 批注的正式定义
首先看一下注释的官方描述:

An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.

翻译:

批注是一种可以添加到java代码中的元数据、类、方法、变量、参数和包可以用批注进行修饰。批注对其修改的代码没有直接影响。

以下是从官方描述中得出的结论:

注释是元数据的一种形式。也就是说,批注属于java类似于类、接口、数组和枚举的数据类型。
注释用于修改类、方法、变量、参数和包。
批注不会对修改后的代码产生直接影响。
1.2 注解的使用范围
继续查看其使用范围的官方描述:

Annotations have a number of uses, among them:Information for the complier - Annotations can be used by the compiler to detect errors or suppress warnings.Compiler-time and deployment-time processing - Software tools can process annotation information to generate code, XML files, and so forth.Runtime processing - Some annotations are available to be examined at runtime.

翻译:

注释有许多用途,包括:为编译器提供信息。 - 编译器可以检测到注释中是否有错误或隐藏警告。编译时和部署时处理 - 软件工具可以处理注释信息以生成代码,XML文件等。在运行时处理 - 一些注释可以在运行时检测到。

2 如何自定义批注
在前一节的基础上,我们对注释有了基本的理解:注释实际上是可以在程序代码中的关键节点(类、方法、变量、参数、包)上标记的标记,然后程序可以在编译时或运行时检测这些标记,以执行一些特殊操作。因此,可以推导出使用自定义注释的基本流程:

第一步是定义注释--相当于定义标签;
第二步是配置注释--标记所需的程序代码;
第三步是解析注释-在编译时或运行时检测标记,并执行特殊操作。

2.1 基本语法
注释类型的声明部分:

注解在Java在中,它类似于类、接口和枚举,因此其声明语法基本相同,只是使用的关键字不同。@interface。在底层实现上,所有定义的注释都会自动继承。java.lang.annotation.Annotation接口。

public @interface CherryAnnotation {
}

注释类型的实现部分:

根据我们在定制类中的经验,类的实现部分只不过是编写构造、属性或方法。但是,在自定义批注中,实现部分只能定义一项内容:批注类型元素(annotation type element)。让我们来看看它的语法:

public @interface CherryAnnotation {
public String name();
int age();
int[] array();
}

也许您认为这是在接口中定义抽象方法的语法?别担心,让我们来看看以下几点:

public @interface CherryAnnotation {
public String name();
int age() default 18;
int[] array();
}

请参阅关键字default你有没有?你还认为这是一种抽象的方法吗?

批注定义:批注类型元素!

定义注释类型元素时应注意以下几点:

访问修饰符必须为public,不写入默认设置public;
元素的类型只能是基本数据类型,String、Class、枚举类型、注解类型(反映注解的嵌套效果)以及上述类型的位数组;
该元素的名称通常定义为名词。如果批注中只有一个元素,请命名它value(以后使用,操作方便);
()它不是定义方法参数的地方,也不能在括号中定义任何参数,只是一种特殊的语法;
default表示默认值,则该值必须与2点定义类型一致;
如果没有缺省值,则意味着在使用后续批注时必须为类型元素赋值。
如您所见,注释类型元素的语法非常奇怪,即它具有属性的特征(可以赋值),还有方法论上的特点(带一对括号)。然而,这种设计是合理的,我们在后面的章节中可以看到:定义了注释后,操作元素类型在使用时类似于操作属性,操作元素类型在解析时类似于操作方法。

2.2 公共元注释
最基本的注释定义之一仅包括上述两个部分:1,批注的名称;2,批注中包含的类型元素。但是,我们使用JDK当你带来自己的批注时,我发现有些批注只能写在方法上(例如,@Override);有些可以写在类的顶部(例如@Deprecated)。当然,除此之外还有很多详细的定义,那么这些定义应该如何做呢?接下来,就会出现人民币的注解!
Meta-Note:专门修改注释的注释。它们都是专门为更好地设计定制注释的细节而设计的。我们将一一为您介绍。

2.2.1 @Target
@Target批注专门用于定义可以应用哪些自定义批注。Java在元素之上。它按如下方式使用枚举类型定义:

public enum ElementType {
/* 类、接口(包括注释类型)或枚举声明 /
TYPE,

/* 财产的声明 /
FIELD,

/* 方法说明书 /
METHOD,

/* 方法表单参数声明 /
PARAMETER,

/* 构造方法说明书 /
CONSTRUCTOR,

/* 局部变量声明 /
LOCAL_VARIABLE,

/* 批注类型声明 /
ANNOTATION_TYPE,

/* 包的声明 /
PACKAGE
}

//@CherryAnnotation仅限于在类、接口或方法上使用。
@Target(value = {ElementType.TYPE,ElementType.METHOD})
public @interface CherryAnnotation {
String name();
int age() default 18;
int[] array();
}

2.2.2 @Retention
@Retention注释,翻译为耐力、保持。也就是说,用于修改定制批注的生命力。
注释的生命周期有三个阶段:1、Java源文档阶段;2、编译到class文档阶段;3,运行阶段。还用过RetentionPolicy枚举类型定义了三个阶段:

public enum RetentionPolicy {
/**

  • Annotations are to be discarded by the compiler.
  • (编译器将忽略注释)
    */
    SOURCE,

/**

  • Annotations are to be recorded in the class file by the compiler
  • but need not be retained by the VM at run time.  This is the default
  • behavior.
  • (注释将由编译器记录在中。class文件,但不会在运行时由虚拟机保留,这是默认行为)
    */
    CLASS,

/**

  • Annotations are to be recorded in the class file by the compiler and
  • retained by the VM at run time, so they may be read reflectively.
  • (注释将由编译器记录在中。class文件,并在运行时由虚拟机保留,因此可以通过反射读取它们)
  • @see java.lang.reflect.AnnotatedElement
    */
    RUNTIME
    }

让我们再详述一遍:

如果定义了批注RetentionPolicy.SOURCE,它将是有限的。Java在源文件中,则该批注在运行时将不参与编译或扮演任何角色。此批注与批注具有相同的效果,并且只能读取Java看到文件的人;
如果定义了批注RetentionPolicy.CLASS,它将被汇编。Class文件,则编译器可以在编译时但在运行时基于批注执行一些处理操作JVM(Java虚拟机)将忽略它,并且我们无法在运行时读取它;
如果定义了批注RetentionPolicy.RUNTIME,则可以将该批注加载到Class物体。然后,在程序运行阶段,我们可以通过反射获得该批注,并通过确定该批注中是否有该批注或属性的值来执行不同的代码段。在我们的实际开发中,几乎总是使用定制注释。RetentionPolicy.RUNTIME;
默认情况下,使用自定义批注。RetentionPolicy.CLASS。
2.2.3 @Documented
@Documented批注用于指定自定义批注是否可以跟随已定义的java文件生成JavaDoc在文件中。

2.2.4 @Inherited
@Inherited批注指定,如果在父类的声明部分中编写了自定义批注,则子类的声明部分可以自动拥有该批注。@Inherited该注释仅适用于那些@Target被定义为ElementType.TYPE自定义注释起作用。

3 使用自定义注释的配置。
查看使用注释的过程:

第一步是定义注释--相当于定义标签;
第二步是配置注释--标记所需的程序代码;
第三步是解析注释-在编译时或运行时检测标记,并执行特殊操作。
到目前为止,我们只完成了第一步。接下来,我们将学习第二步,即配置注释以及如何在另一个类中配置它们。

3.1 在具体的Java在类上使用批注
首先,定义一个注释,并为注释修饰定义一个简单的注释。Java类

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD})
@Documented
public @interface CherryAnnotation {
String name();
int age() default 18;
int[] score();
}

public class Student{
public void study(int times){
for(int i = 0; i < times; i++){
System.out.println("Good Good Study, Day Day Up!");
}
}
}

在简单的分析下:

CherryAnnotation的@Target定义为ElementType.METHOD,则应写在方法定义的上方,即:public void study(int times)之上;
既然我们在CherryAnnotation有在中定义的注释类型元素,并且某些元素没有默认值,这要求我们在使用它们时在标记名之后键入。(),并且在()在“元素名称”中。=“元素值”的形式是一个接一个地填入所有没有缺省值的注释型元素(有缺省值的元素也可以重新赋值),“,“数字的除法;
因此,最终的写作形式如下:

public class Student {
@CherryAnnotation(name = "cherry-peng",age = 23,score = {99,66,77})
public void study(int times){
for(int i = 0; i < times; i++){
System.out.println("Good Good Study, Day Day Up!");
}
}
}

3.2 特殊语法
特殊语法一:

如果批注本身没有批注类型元素,则在使用批注时可以省略它。(),直接写:@注解名称、it和标准语法。@注解名()等效!

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface FirstAnnotation {
}

//等效于@FirstAnnotation()
@FirstAnnotation
public class JavaBean{
//省略实施部分
}

特殊语法2:

如果批注簿本身只有一个批注类型元素,并且名为value,则可以直接使用批注:@注解名(注解值),相当于:@注解名(value = 注解值)

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface SecondAnnotation {
String value();
}

//等效于@ SecondAnnotation(value = "this is second annotation")
@SecondAnnotation("this is annotation")
public class JavaBean{
//省略实施部分
}

特殊用途III:

如果批注中的批注类型元素是数组类型,在使用时只需要填写一个值,那么在使用批注时可以直接写入:@注解名(类型名 = 类型值)、信息技术和标准写作:@注解名(类型名 = {类型值})等效!

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface ThirdAnnotation {
String[] name();
}

//等效于@ ThirdAnnotation(name = {"this is third annotation"})
@ ThirdAnnotation(name = "this is third annotation")
public class JavaBean{
//省略实施部分
}

特殊用法四:

如果一个批注@Target是定义为Element.PACKAGE,则在中配置该批注。package-info.java在课堂上,不是直接在课堂上。package代码已在上面配置。

4 自定义批注的运行时解析
本章是使用注释的核心。阅读本章后,您将了解如何在程序运行时检测注释并执行一系列特殊操作!

4.1 查看批注的保留情况
首先回顾一下前面的定制注解@CherryAnnotation并在班级中进行配置。Student打开时,代码如下:

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD})
@Documented
public @interface CherryAnnotation {
String name();
int age() default 18;
int[] score();
}

package pojos;
public class Student {
@CherryAnnotation(name = "cherry-peng",age = 23,score = {99,66,77})
public void study(int times){
for(int i = 0; i < times; i++){
System.out.println("Good Good Study, Day Day Up!");
}
}
}

注意维持武力的三个阶段:

Java源文档阶段;
编译到class文档阶段;
运行阶段。
只有当批注的持力处于运行阶段时,即E。使用@Retention(RetentionPolicy.RUNTIME)修改批注时,它仅在JVM运行时,会检测注释并执行一系列特殊操作。

4.2 反射操作获得注释。
因此,很明显,我们的目标是在运行期间探索和使用编译期间的内容(编译期间配置的注释),并使用它们。Java灵魂科技--反思!

public class TestAnnotation {
public static void main(String[] args){
try {
//获取Student的Class对象
Class stuClass = Class.forName("pojos.Student");

//解释说形式化参数不能写在这里。Integer.class,应写为int.class
Method stuMethod = stuClass.getMethod("study",int.class);

if(stuMethod.isAnnotationPresent(CherryAnnotation.class)){
System.out.println("Student类已配置。CherryAnnotation注解!");
//获取元素上指定类型的批注
CherryAnnotation cherryAnnotation = stuMethod.getAnnotation(CherryAnnotation.class);
System.out.println("name: " + cherryAnnotation.name() + ", age: " + cherryAnnotation.age()

  • ", score: " + cherryAnnotation.score()[0]);
    }else{
    System.out.println("Student类上没有配置CherryAnnotation注解!");
    }
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    } catch (NoSuchMethodException e) {
    e.printStackTrace();
    }
    }
    }

解释:

如果在方法上配置了我们想要获取的注释,那么我们希望从开始。Method对象;如果它是在属性上配置的,则需要从相应的属性中获取它。Field要获取的对象,如果它是在类型上配置的,则需要来自。Class物件上去拿。简而言之,无论你是谁,你都可以从你是谁那里得到它!
isAnnotationPresent(Class<? extends Annotation> annotationClass)方法是具体确定元素上是否配置了指定的注释;
getAnnotation(Class annotationClass)该方法是获取元素上指定的注释。然后调用该注释的注释类型元素方法,获取配置时的值数据;
还有一种关于反射对象的方法。getAnnotations(),该方法可以获取对象上配置的所有注释。它将向我们返回一个注释数组。需要注意的是,数组的类型是Annotation类型,这个Annotation是一位来自java.lang.annotation包的界面。
————————————————
版权声明:本文是CSDN博主「cherry-peng“原文,跟上。 CC 4.0 BY-SA 版权协议,转载请附上原始来源链接和本声明。
原始链接:
https://blog.csdn.net/xsp\_happyboy/article/details/80987484

版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除

热门