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 中。
作用在代码的注解是
- @Override - 检查该方法是否是重载方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
- @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
- @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中定义了四种元注解,用于定义其他注解,下面一一进行解释:
作用在其他注解的注解(或者说 元注解)是:
- @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
- @Documented - 标记这些注解是否包含在用户文档中。
- @Target - 标记这个注解应该是哪种 Java 成员。
- @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代码编写的完整截图: