如何自定义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 中。

作用在代码的注解是

@Override - 检查该方法是否是重载方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。

@Deprecated - 标记过时方法。如果使用该方法,会报编译警告。

@SuppressWarnings - 指示编译器去忽略注解中声明的警告。

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

c1e2ecc3f1bca052d78dd52b89bc93a3.png

2.1 @Override详解

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

62f2073fdd67bd5db5477ee50c04c9a7.png

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

88bc5dc32d25c4c924cdbec8efa796d5.png

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

@Target(ElementType.METHOD)//说明该注解只能标注在方法上

@Retention(RetentionPolicy.SOURCE)//说明该注解只在源码基本是生效,为编译检查注解

public @interface Override {}//定义注解,并无任何参数

2.2 @Deprecated详解

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

6950fc1903e108848ed51b625e3d5020.png

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

7b7ab29bae115ec48b385aefdb954f56.png

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

@Documented//说明该注解会生成javadoc文档

@Retention(RetentionPolicy.RUNTIME)//说明该注解

@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})//说明该注解可以标注在方法上、类上、字段上等上

public @interface Deprecated {}//定义注解,并无任何参数

2.3 @SuppressWarnings详解

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

a72dce917ee808e10ef4741ae1ca4a4e.png

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

086751f6fd7f3d92a5bb9a22ac6aee54.png

e1911efe95514ac8e95233c780ffed88.png

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

@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枚举类源码中一看便知,无需记忆:

ef7444b5a8c1c3a6c7c2aab5b6b6bf48.png

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

package java.lang.annotation;

public enum ElementType {

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

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

METHOD, /* 方法声明 */

PARAMETER, /* 参数声明 */

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

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

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

PACKAGE /* 包声明 */

}

3.2、@Retention参数详解

该元注解标识着被定义的注解在哪格阶段时进行生效,源码级

@Retention(RetentionPolicy.SOURCE)

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

88a1a766c47e0e53d5f0534094001943.png

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

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代码编写的完整截图:

bf6e0deaf5e3a228217f68014bafdbd1.png

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值