java基础复习-自定义注解1(如何自定义注解?)

java基础复习-自定义注解1(如何自定义注解?)

写在前面

1、注解在java基础中属于比较简单的内容,因此作为开篇。但是,该板块内容,往往是初学者容易忽略的一部分,因为在初学阶段,初学者所接触的注解过少,无法体会到注解的强大所在。但是,随着学习java的深入,经历了各种配置地狱般的框架,也终究体会到了注解技术的方便与快捷。因此,萌生了自己自定义注解的学习回顾,方便自己在后期开发中能够通过自定义注解简化自己的代码编写。

2、自定义注解教程分为多节进行讲解,从如何自定义注解、反射技术、结合反射技术编写注解解析器到如何在SpringBoot项目中进行应用,最后,通过注解技术实现一个orm的微型框架进行实战。本节讲述如何自定义注解:

1、注解介绍

考虑到有部分大学java课程中没有收录该部分内容,因此作为一个简短的介绍。

1.1、注解与注释的区别

注释,相信大家都有所了解,是开发人员写给开发人员对自己所写代码阐述的一段文字说明,在编译时不加载进.clsss文件中。

注解,与注释只有一字之差,其本质上并没有区别,他只不过携带着某种信息,供编译器阅读和提取信息,参与.class文件的生成。

综上,我的理解为:注解也是注释,是供编译器阅读和获取信息的注释,是JDK5.0 引入的一种注释机制。 下面引用较为官方的一段话进行说明:

Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。

Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。

2、对JDK中内置的三种常见注解进行源码分析

Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。

作用在代码的注解是

  1. @Override - 检查该方法是否是重载方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
  2. @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
  3. @SuppressWarnings - 指示编译器去忽略注解中声明的警告。

上面三种注解的使用见下图,本节将分别进行源码分析

2.1 @Override详解

该注解用于编译检查,如果子类发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。如下图:(所有类都集成于Object类,在此,故意将toString()方法写错,则会报编译错误)

点进该注解中查看源码,可以看到:

下面通过代码注释对每一行代码进行说明:

@Target(ElementType.METHOD)	//说明该注解只能标注在方法上		
@Retention(RetentionPolicy.SOURCE)	//说明该注解只在源码基本是生效,为编译检查注解
public @interface Override {}	//定义注解,并无任何参数

2.2 @Deprecated详解

该注解用于标记过时的方法,被标上该注解的方法,会在使用时出现过时警告(在IDEA开发工具中过时方法中有一道横线):

点进该注解中查看源码,可以看到:

下面通过代码注释对每一行代码进行说明:

@Documented		//说明该注解会生成javadoc文档
@Retention(RetentionPolicy.RUNTIME)	//说明该注解
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})	//说明该注解可以标注在方法上、类上、字段上等上
public @interface Deprecated {}	//定义注解,并无任何参数

2.3 @SuppressWarnings详解

该注解用于压制注解,注解的参数“all”表示压制全部注解,在IDEA中,重复代码过多会出现黄色波浪线,过时方法会出现横线,该注解都能进行压制。如下图:(将类级别上的该注解打开,过时注解标注的方法就没有出现波浪线了)

点进该注解中查看源码,可以看到:


下面通过代码注释对每一行代码进行说明:

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})	//该注解可以作用在类上,方法上,字段上
@Retention(RetentionPolicy.SOURCE)	//说明该注解只在源码基本是生效,为编译检查注解
public @interface SuppressWarnings {	//定义注解,并且有一个参数
	String[] value();		//注意:在注解的定义中,该行并不表示为一个抽像方法,二是一个字段
}

3、元注解

对于上面三种JDK内置注解的源码分析,可以看出这三种注解的定义都有些共同点,显然,定义注解的语法为@interface,其作用范围和其他信息由其上面的注解进行限定。JDK中定义了四种元注解,用于定义其他注解,下面一一进行解释:

作用在其他注解的注解(或者说 元注解)是:

  1. @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
  2. @Documented - 标记这些注解是否包含在用户文档中。
  3. @Target - 标记这个注解应该是哪种 Java 成员。
  4. @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)

下面解释一下,需要填写参数的两个元注解:@Target和@Retention

3.1、@Target参数详解

该注解用于标注其他注解能够标注的位置,如果只有一个参数,直接写在@Target()内,如果需要标注在多个位置上,就在()中传递一个数组,如:

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})

对于该注解的参数说明,点击ElementType枚举类源码中一看便知,无需记忆:

下面对该枚举类的参数进行说明:

package java.lang.annotation;

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

    FIELD,              /* 字段声明(包括枚举常量)  */

    METHOD,             /* 方法声明  */

    PARAMETER,          /* 参数声明  */

    CONSTRUCTOR,        /* 构造方法声明  */

    LOCAL_VARIABLE,     /* 局部变量声明  */

    ANNOTATION_TYPE,    /* 注释类型声明  */

    PACKAGE             /* 包声明  */
}

3.2、@Retention参数详解

该元注解标识着被定义的注解在哪格阶段时进行生效,源码级<clsss文件级<<运行时级,因此该类的参数只有三种,不允许标注多个参数,使用方法如下:

@Retention(RetentionPolicy.SOURCE)

对于该注解的参数说明,点击RetentionPolicy枚举类源码中一看便知,也无需记忆:

下面对该枚举类的参数进行说明:

package java.lang.annotation;
public enum RetentionPolicy {
    SOURCE,            /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了  */

    CLASS,             /* 编译器将Annotation存储于类对应的.class文件中。默认行为  */

    RUNTIME            /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */
}

4、进行自定义注解的模仿编写

介绍完注解的相关知识,我们仿照JDK中内置的注解定义模式定义自己的自定义注解MyAnnotation。

//表示我们定义的注解可以用在哪些地方
@Target(value = {ElementType.METHOD,ElementType.TYPE})  //可以标注在方法上,类上
//表示我们的注解在什么时候有效
@Retention(value = RetentionPolicy.RUNTIME)     //在运行时生效
//表示我们自定义的直接是否生成在java的文档中
@Documented
//表示子类可以继承父类中的方法
@Inherited
@interface MyAnnotation {
    String name();      //注解的名字,为必填参数
    String date() default "2020-02-02";     //注解日期,使用时没有传递该参数,为此默认值
}

MyAnnotation为自己自定义的一个注解,关于该注解的解释见代码中的注释,下面来使用该注解:

//使用自定义注解
public class test02 {
    @MyAnnotation(name = "xgp")
    public void test() { }
}

自定义注解MyAnnotation代码编写的完整截图:

阅读自此,已完成了自定义注解的简单编写,但是可能有读者疑惑,编译器怎样获取注解上的信息和怎样为我们进行便捷的开发,就请看下一节的反射技术的学习和后续注解解析器的编写。

原文地址:https://www.cnblogs.com/xgp123/p/12253310.html