zoukankan      html  css  js  c++  java
  • 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代码编写的完整截图:

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

  • 相关阅读:
    luogu P4587 [FJOI2016]神秘数
    luogu P4042 [AHOI2014/JSOI2014]骑士游戏
    luogu P2597 [ZJOI2012]灾难
    一则胡乱科普
    NJU Static Program Analysis 09: Pointer Analysis II
    NJU Static Program Analysis 08: Pointer Analysis I
    NJU Static Program Analysis 07: Interprocedural Analysis
    NJU Static Program Analysis 06: Data Flow Analysis IV
    LianYunGang OI Camp: Contest #2
    NJU Static Program Analysis 05: Data Flow Analysis III
  • 原文地址:https://www.cnblogs.com/xgp123/p/12253310.html
Copyright © 2011-2022 走看看