欢迎访问www.allbetgaming.com!

首页科技正文

欧博开户:教科书级解说,秒懂最详细Java的注解

admin2020-07-2868

所有知识系统文章,GitHub已收录,迎接Star!再次谢谢,愿你早日进入大厂!

GitHub地址: https://github.com/Ziphtracks/JavaLearningmanual

Java注解

一、Java注解概述

注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特征,与类、接口、枚举是在同一个条理。它可以声明在包、类、字段、方式、局部变量、方式参数等的前面,用来对这些元素举行说明,注释。

二、注解的作用分类

  • 编写文档: 通过代码里标识的元数据天生文档【天生文档doc文档】
  • 代码剖析: 通过代码里标识的元数据对代码举行剖析【使用反射】
  • 编译检查: 通过代码里标识的元数据让编译器能够实现基本的编译检查【Override等】

编写文档

首先,我们要知道Java中是有三种注释的,分别为单行注释、多行注释和文档注释。而文档注释中,也有@开头的元注解,这就是基于文档注释的注解。我们可以使用javadoc下令来天生doc文档,此时我们文档的内元注解也会天生对应的文档内容。这就是编写文档的作用。

代码剖析

我们频仍使用之一,也是包罗使用反射来通过代码里标识的元数据对代码举行剖析的,此内容我们在后续展开解说。

编译检查

至于在编译时代在代码中标识的注解,可以用来做特定的编译检查,它可以在编译时代就检查出“你是否按划定做事”,若是不凭据注解划定做事的话,就会在编译时代飘红报错,并予以提醒信息。可以就可以为我们代码提供了一种规范制约,制止我们后续在代码中处置太多的代码以及功效的规范。好比,@Override注解是在我们笼罩父类(父接口)方式时泛起的,这证实我们笼罩方式是继续于父类(父接口)的方式,若是该方式稍加改变就会报错;@FunctionInterface注解是在编译期检查是否是函数式接口的,若是不遵照它的规范,同样也会报错。

三、jdk的内置注解

3.1 内置注解分类

  • @Override: 符号在成员方式上,用于标识当前方式是重写父类(父接口)方式,编译器在对该方式举行编译时会检查是否相符重写规则,若是不相符,编译报错。
  • @Deprecated: 用于符号当前类、成员变量、成员方式或者组织方式过时若是开发者挪用了被符号为过时的方式,编译器在编译期举行忠告。
  • @SuppressWarnings: 压制忠告注解,可放置在类和方式上,该注解的作用是阻止编译器发出某些忠告信息。

3.2 @Override注解

符号在成员方式上,用于标识当前方式是重写父类(父接口)方式,编译器在对该方式举行编译时会检查是否相符重写规则,若是不相符,编译报错。

这里注释一下@Override注解,在我们的Object基类中有一个方式是toString方式,我们通常在实体类中去重写此方式来到达打印工具信息的效果,这时刻也会发现重写的toString方式上方就有一个@Override注解。如下所示:

image-20200604203535421

于是,我们试图去改变重写后的toString方式名称,将方式名改为toStrings。你会发现在编译期就报错了!如下所示:

image-20200604203645332

那么这说明什么呢?这就说明该方式不是我们重写其父类(Object)的方式。这就是@Override注解的作用。

3.3 @Deprecated注解

用于符号当前类、成员变量、成员方式或者组织方式过时若是开发者挪用了被符号为过时的方式,编译器在编译期举行忠告。

我们注释@Deprecated注解就需要模拟一种场景了。假设我们公司的产物,现在是V1.0版本,它为用户提供了show1方式的功效。这时刻我们为产物的show1方式的功效又举行了扩展,计划公布V2.0版本。然则,我们V1.0版本的产物需要甩掉吗?也就是说我们V1.0的产物功效还继续让用户使用吗?谜底一定是不能甩掉的,由于有一部分用户是一直用V1.0版本的。若是甩掉了该版本会损失许多的用户量,以是我们不能甩掉该版本。这时刻,我们对功效举行了扩展后,公布了V2.0版本,我们给予用户的通知就可以了,也就是见告用户我们在V2.0版本中为功效举行了扩展。可以让用户自行选择版本。

然则,除了公布见告用户版本情形之外,我们还需要在原来版本的功效上给予提醒,在上面的模拟场景中我们需要在show1方式上方加@Deprecated注解给予提醒。通过这种方式也见告用户“这是旧版本时刻的功效了,我们不建议再继续使用旧版本的功效”,这句话的意思也就正是给用户做了提醒。用户也会这么想“奥,这版本的这个功效欠好用了,一定有新版本,又更好用的功效。我要去官网查一下下载新版本”,还会有用户这么想“我明晰了,又更新出更好的功效了,然则这个版本的功效我已经够用了,不需要重新下载新版本了”。

那么我们怎么查看我上述所说的在功效上给予的提醒呢?这时刻我需要去建立一个方式,然后去挪用show1方式,并查看挪用时它是若何提醒的。

欧博开户:教科书级解说,秒懂最详细Java的注解 第1张

图已经贴出来了,你是否发现的新旧版本功效的异同点呢?很明显,在方式中的提醒是在挪用的方式名上加了一道横线把该方式划掉了。这就体现了show1方式过时了,已经不建议使用了,我们为你提供了更好的。

回想起来,在我们的api中也会有方式是过时的,好比我们的Date日期类中的方式有许多都已经过时了。如下图:

欧博开户:教科书级解说,秒懂最详细Java的注解 第2张 image-20200604210154348 欧博开户:教科书级解说,秒懂最详细Java的注解 第3张 image-20200604210416762

如你所见,是不是有许多方式都过时了呢?那它的方式上是加了@Deprecated注解吗?来随着我的脚步,我带你们看一下。

欧博开户:教科书级解说,秒懂最详细Java的注解 第4张

我们已经知道的Date类中的这些方式已经是过时的了,若是我们使用该方式并执行该程序的话。执行的过程中就会提醒该方式已过时的内容,然则只是提醒,并不影响你使用该方式。如下:

欧博开户:教科书级解说,秒懂最详细Java的注解 第5张 image-20200604221938895

OK!这也就是@Deprecated注解的作用了。

3.4 @SuppressWarnings注解

压制忠告注解,可放置在类和方式上,该注解的作用是阻止编译器发出某些忠告信息,该注解为单值注解,只有 一个value参数,该参数为字符串数组类型,参数值常用的有如下几个。

  • unchecked:未检查的转化,如聚集没有指定类型还添加元素
  • unused:未使用的变量
  • resource:有泛型未指定类型
  • path:在类路径,原文件路径中有不存在的路径
  • deprecation:使用了某些不赞成使用的类和方式
  • fallthrough:switch语句执行到底没有break关键字
  • rawtypes:没有写泛型,好比: List list = new ArrayList();
  • all:所有类型的忠告

压制忠告注解,顾名思义就是压制忠告的泛起。我们都知道,在Java代码的编写过程中,是有许多黄色忠告泛起的。然则我不知道你的导师是否教过你,程序员只需要处置红色的error,不需要剖析黄色的warning。若是你的导师说过此问题,那是有缘故原由的。由于在你学习阶段,我们认清处置红色的error即可,这样可以减轻你学习阶段在脑部的影象内容。若是你刚刚加入学习Java的行列中,需要大脑影象的器械就有太多了,也就是我们现在不需要分外影象其他的器械,只影象重点即可。至于黄色warning嘛,在你的学习过程中逐步就会有所领会的,而不是死记硬背的。

那为了注释@SuppressWarnings注解,我们还使用上一个例子,由于在谁人例子中就有黄色的warning泛起。

欧博开户:教科书级解说,秒懂最详细Java的注解 第6张

而每一个黄色的warning都市有忠告信息的。好比,这一个图中的忠告信息,就见告你show2()方式没有被使用,简朴来说,你建立的show2方式,然则你在代码中并没有挪用过此方式。以后你便会遇到林林总总黄色的warning。然后, 我们就可以使用差别的注解参数来压制差别的注解。然则在该注解的参数中,提供了一个all参数可以压制所有类型的忠告。而这个注解是需要加到类的上方,并赋予all参数,即可压制所有忠告。如下:

欧博开户:教科书级解说,秒懂最详细Java的注解 第7张 image-20200604213943722

我们加入注解并赋予all参数后,你会发现use方式和show2方式的忠告没有了,实际上导Date包的忠告还在,由于我们Date包导入到了该类中,然则我们并没有建立Date工具,也就是并没有写入Date在代码中,你也会发现那一行是灰色的,也就证实了我们没有去使用导入这个包的任何信息的说法,泛起这种情形我们就需要把这个没有用的导包内容删除掉,使用Ctrl + X删除导入没有用到的包即可。另有一种设施就是在包的上方修饰压制忠告注解,然则我以为在一个没有用的包上加压制注解是毫无意义的,以是,我们直接删除就好。

然后,我们还见到上图,注解那一行泛起了忠告信息提醒。这一行的意思是冗余的忠告压制。这就是说我们压制以下的忠告并没有什么意义而造成的冗余,然则若是我们使用了该类并做了点什么的话,压制注解的冗余忠告就会消逝,事实我们使用了该类,此时就不会早场冗余了。

上述注释@SuppressWarnings注解也差不多就这些了。OK,继续向下看吧。连续为人人解说。

3.5 @Repeatable注解

@Repeatable 解释符号的注解可以多次应用于相同的声明或类型,此注解由Java8版本引入。我们知道注解是不能重复界说的,实在该注解就是一个语法糖,它可以重复多此使用,更适用于我们的特殊场景。

首先,我们先建立一个可以重复使用的注解。

package com.mylifes1110.anno;

import java.lang.annotation.Repeatable;

@Repeatable(Hour.class)
public @interface Hours {
    double[] hours() default 0;
}

你会发现注解要求传入的值是一个类工具,此类工具就需要传入另外一个注解,这里也就是另外一个注解容器的类工具。我们去建立一下。

package com.mylifes1110.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//容器
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Hour {
    Hours[] value();
}

实在,这两个注解的套用,就是将一个通俗的注解封装了一个可重复使用的注解,来到达注解的复用性。最后,我们建立一下测试类,随后带你去看一下源码。

package com.mylifes1110.java;

import com.mylifes1110.anno.Hours;

@Hours(hours = 4)
@Hours(hours = 4.5)
@Hours(hours = 2)
public class Worker {
    public static void main(String[] args) {
        //通过Hours注解类型来获取Worker中的值数组工具
        Hours[] hours = Worker.class.getAnnotationsByType(Hours.class);
        //遍历数组
        for (Hours h : hours) {
            System.out.println(h);
        }
    }
}

测试类,是一个工人测试类,该工人使用注解纪录早中晚的工作时间。测试效果如下:

欧博开户:教科书级解说,秒懂最详细Java的注解 第8张 image-20200606183652359

然后我们进入到源码一探事实。

欧博开户:教科书级解说,秒懂最详细Java的注解 第9张 image-20200606183737877

我们发现进入到源码后,就只瞥见一个返回值为类工具的抽象方式。这也就验证了该注解只是一个可实现重复性注解的语法糖而已。

四、注解分类

4.1 注解分类

注解可以凭据注解参数分为三大类:

  • 符号注解: 没有参数的注解,仅用自身的存在与否为程序提供信息,如@Override注解,该注解没有参数,用于示意当前方式为重写方式。
  • 单值注解: 只有一个参数的注解,若是该参数的名字为value,那么可以省略参数名,如 @SuppressWarnings(value = "all"),可以简写为@SuppressWarnings("all")。
  • 完整注解: 有多个参数的注解。

4.2 符号注解

说到@Override注解是一个符号注解,那我们进入到该注解的源码查看一下。从上往下看该注解源码,发现它继续了导入了java.lang.annotation.*,也就是有使用到该包的内容。然后下面就又是两个看不懂的注解,实在发现注解的界说花样是public修饰的@Interface,最终看到该注解中方式体并没有任何参数,也就是只起到符号作用。

欧博开户:教科书级解说,秒懂最详细Java的注解 第10张

4.3 单值注解

在上面我们用到的@SuppressWarnings注解就是一个单值注解。那我们进入到它的源码看一下是怎么个情形。实在,和符号注解对照,它就多一个value参数而已,而这就是单值注解的必要条件,即只有一个参数。而且这一个参数为value时,我们可以省略value。

欧博开户:教科书级解说,秒懂最详细Java的注解 第11张

4.4 完整注解

上述两个类型注解解说完,至于完整注解嘛,这下就能更明晰了。其中的方式体就是有多个参数而已。

五、自界说注解

5.1 自界说注解花样

花样: public @Interface 注解名 {属性列表/无属性}

注重: 若是注解体中无任何属性,其本质就是符号注解。然则与其标注注解还少了上边修饰的元注解。

如下,这就是一个注解。然则它与jdk自界说注解有点区别,jdk自界说注解的上方另有注解来修饰该注解,而那注解就叫做元注解。元注解我会在后面详细的说到。

欧博开户:教科书级解说,秒懂最详细Java的注解 第12张 image-20200606104149069

这里我们简直不知道@Interface是什么,那我们就把自界说的这个注解反编译一下,看一下反编译信息。反编译操作如下:

欧博开户:教科书级解说,秒懂最详细Java的注解 第13张 image-20200606104818131

反编译后的反编译内容如下:

public interface com.mylifes1110.anno.MyAnno extends java.lang.annotation.Annotation {
}

首先,看过反编译内容后,我们可以直观的得知他是一个接口,由于它的public修饰符后面的关键字是interface。

其次,我们发现MyAnno这个接口是继续了java.lang.annotation包下的Annotation接口。

以是,我们可以得知注解的本质就是一个接口,该接口默认继续了Annotation接口。

既然,是继续的Annotation接口,那我们就去进入到这个接口中,看它界说了什么。以下是我抽取出来的接口内容。我们发现它看似很常见,实在它们不是很常用,作为领会即可。

public interface Annotation {
    boolean equals(Object obj);
    int hashCode();
    String toString();
    Class<? extends Annotation> annotationType();
}

最后,我们的注解中也是可以写有属性的,它的属性差别于通俗的属性,它的属性是抽象方式。既然注解也是一个接口,那么我们可以说接口体中可以界说什么,它同样也可以界说,而它的修饰符与接口一样,也是默认被public abstract修饰。

而注解体中的属性也是有要求的。其属性要求如下:

  • 属性的返回值类型必须是以下几种:
  • 基本数据类型
  • String类型
  • 枚举类型
  • 注解
  • 以上类型的数组
  • 注重: 在这里不能有void的无返回值类型和以上类型以外的类型
  • 界说的属性,在使用时需要给注解中的属性赋值
  • 若是界说属性时,使用default关键字给属性默认初始化值,则使用注解时可以不为属性赋值,它取的是默认值。若是为它再次传入值,那么就发生了对原值的笼罩。
  • 若是只有一个属性需要赋值,而且属性的名称为value,则赋值时value可以省略,可以直接界说值
  • 数组赋值时,值使用{}存储值。若是数组中只有一个值,则可以省略{}

5.2 自界说注解属性的返回值

属性返回值既然有以上几种,那么我就在这里写出这几种演示一下是若何写的。

首先,界说一个枚举类和另外一个注解备用。

package com.mylifes1110.enums;

public enum Lamp {
    RED, GREEN, YELLOW
}
package com.mylifes1110.anno;

public @interface MyAnno2 {
}

其次,我们来界说上述几种类型,如下:

package com.mylifes1110.anno;

import com.mylifes1110.enums.Lamp;

public @interface MyAnno {
    //基本数据类型
    int num();

    //String类型
    String value();

    //枚举类型
    Lamp lamp();

    //注解类型
    MyAnno2 myAnno2();

    //以上类型的数组
    String[] values();
    Lamp[] lamps();
    MyAnno2[] myAnno2s();
    int[] nums();
}

5.3 自界说注解的属性赋值

这里我们演示一下,首先,我们使用该注解来举行演示。

package com.mylifes1110.anno;

public @interface MyAnno {
    //基本数据类型
    int num();

    //String类型
    String value();
}

随后建立一个测试类,在类的上方写上注解,你会发现,注解的参数中会让你写这两个参数(int、String)。

欧博开户:教科书级解说,秒懂最详细Java的注解 第14张 image-20200606113037920

此时,传参是这样来做的。花样为:名称 = 返回值类型参数。如下:

欧博开户:教科书级解说,秒懂最详细Java的注解 第15张

上述所说,若是使用default关键字给属性默认初始化值,就不需要为其参数赋值,若是赋值的话,就把默认初始化的值笼罩掉了。

欧博开户:教科书级解说,秒懂最详细Java的注解 第16张

固然另有一个规则,若是只有一个属性需要赋值,而且属性的名称为value,则赋值时value可以省略,可以直接界说值。那么,我们的num已经有了默认值,就可以不为它传值。我们发现,注解中界说的属性就剩下了一个value属性值,那么我们就可以来演示这个规则了。

欧博开户:教科书级解说,秒懂最详细Java的注解 第17张 image-20200606113849685

这里,我并没有写属性名称value,而是直接为value赋值。若是我将num的default关键字修饰去掉呢,那意思也就是说在使用该注解时必须为num赋值,这样可以省略value吗?那我们看一下。

欧博开户:教科书级解说,秒懂最详细Java的注解 第18张 image-20200606114216801

效果,就是我们所想的,它报错了,必须让我们给num赋值。实在想想这个规则也是很容易懂的,界说一个为value的值,就可以省略其value名称。若是界说多个值,它们可以省略名称就无法区分界说的是谁人值了,关键是另有数组,数组内界说的是多个值呢,对吧。

5.4 自界说注解的多种返回值类型赋值

这里我们演示一下,上述的多种返回值类型是若何赋值的。这里我们界说这几个参数来看一下,是若作甚属性赋值的。

欧博开户:教科书级解说,秒懂最详细Java的注解 第19张

num是一个int基本数据类型,即num = 1

value是一个String类型,即value = "str"

lamp是一个枚举类型,即lamp = Lamp.RED

myAnno2是一个注解类型,即myAnno2 = @MyAnno2

values是一个String类型数组,即values = {"s1", "s2", "s3"}

values是一个String类型数组,其数组中只有一个值,即values = "s4"

注重: 值与值之间是,离隔的;数组是用{}来存储值的,若是数组中只有一个值可以省略{};枚举类型是枚举名.枚举值

欧博开户:教科书级解说,秒懂最详细Java的注解 第20张

六、元注解

6.1 元注解分类

元注解就是用来形貌注解的注解。一样平常使用元注解来限制自界说注解的使用局限、生命周期等等。

而在jdk的中java.lang.annotation包中界说了四个元注解,如下:

元注解 形貌
@Target 指定被修饰的注解的作用局限
@Retention 指定了被修饰的注解的生命周期
@Documented 指定了被修饰的注解是可以Javadoc等工具文档化
@Inherited 指定了被修饰的注解修饰程序元素的时刻是可以被子类继续的

6.2 @Target

@Target 指定被修饰的注解的作用局限。其作用局限可以在源码中找到参数值。

属性 形貌
CONSTRUCTOR 用于形貌组织器
FIELD(常用) 用于形貌属性
LOCAL_VARIABLE 用于形貌局部变量
METHOD(常用) 用于形貌方式
PACKAGE 用于形貌包
PARAMETER 用于形貌参数
TYPE(常用) 用于形貌类、接口(包罗注解类型) 或enum声明
ANNOTATION_TYPE 用于形貌注解类型
TYPE_USE 用于形貌使用类型

由此可见,该注解体内只有一个value属性值,然则它的类型是一个ElementType数组。那我们进入到这个数组中继续查看。

欧博开户:教科书级解说,秒懂最详细Java的注解 第21张

进入到该数组中,你会发现他是一个枚举类,其中界说了上述表格中的各个属性。

欧博开户:教科书级解说,秒懂最详细Java的注解 第22张

领会了@Target的作用和属性值后,我们来使用一下该注解。首先,我们要先用该注解来修饰一个自界说注解,界说该注解的指定作用在类上。如下:

欧博开户:教科书级解说,秒懂最详细Java的注解 第23张

而你考察如下测试类,我们把注解作用在类上时是没有错误的。而当我们的注解作用在其他地方就会报错。这也就说明晰,我们@Target的属性起了作用。

注重: 若是我们界说多个作用局限时,也是可以省略该参数名称了,由于该类型是一个数组,虽然能省略名称然则,我们还需要用{}来存储。

欧博开户:教科书级解说,秒懂最详细Java的注解 第24张

6.3 @Retention

@Retention 指定了被修饰的注解的生命周期

属性 形貌
RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器举行编译时它将被抛弃忽视。
RetentionPolicy.CLASS 注解只被保留到编译举行时的class文件,但 JVM 加载class文件时刻被遗弃,也就是在这个阶段不会读取到该class文件。
RetentionPolicy.RUNTIME(常用) 注解可以保留到程序运行的时刻,它会被加载进入到 JVM 中,以是在程序运行时可以获取到它们。

注重: 我们常用的界说即是RetentionPolicy.RUNTIME,由于我们使用反射来实现的时刻是需要从JVM中获取class类工具并操作类工具的。

首先,我们要领会反射的三个生命周期阶段,这部分内容我在Java反射机制中也是做了异常详细的说明,有兴趣的小伙伴可以去看看我写的Java反射机制,相信你在其中也会有所收获。

这里我再次强调一下这三个生命周期是源码阶段 - > class类工具阶段 - > Runtime运行时阶段

那我们进入到源码,看看@Retention注解中是否有这些参数。

欧博开户:教科书级解说,秒懂最详细Java的注解 第25张

我们看到该注解中的属性只有一个value,而它的类型是一个RetentionPolicy类型,我们进入到该类型中看看有什么参数,是否与表格中的参数相同呢?

欧博开户:教科书级解说,秒懂最详细Java的注解 第26张 image-20200606145449931

至于该注解怎么使用,实在是相同的,用法如下:

欧博开户:教科书级解说,秒懂最详细Java的注解 第27张

这就证实了我们的注解可以保留到Runtime运行阶段,而我们在反射中大多数是界说到Runtime运行时阶段的,由于我们需要从JVM中获取class类工具并操作类工具。

6.4 @Documented

@Documented 指定了被修饰的注解是可以Javadoc等工具文档化

@Documented注解是对照好明白的,它是一个符号注解。被该符号注解符号的注解,天生doc文档时,注解是可以被加载到文档中显示的。

欧博开户:教科书级解说,秒懂最详细Java的注解 第28张 image-20200606152526551

还拿api中过时的Date中的方式来说,在api中显示Date中的getYear方式是这样的。

欧博开户:教科书级解说,秒懂最详细Java的注解 第29张

正如你看到的,注解在api中显示了出来,证实该注解是@Documented注解修饰并文档化的。那我们就看看这个注解是否被@Documented修饰吧。

欧博开户:教科书级解说,秒懂最详细Java的注解 第30张

然后,我们发现该注解简直是被文档化了。以是在api中才会显示该注解的。若是不信,你可以自己使用javadoc下令来天生一下doc文档,看看被该注解修饰的注解是否存在。

至于Javadoc文档天生,我在javadoc文档天生一文中有过详细纪录,人人可以举行参考,天生doc文档查看。

6.5 @Inherited

@Inherited 指定了被修饰的注解修饰程序元素的时刻是可以被子类继续的

首先进入到源码中,我们也可以清晰的知道,该注解也是一个符号注解。而且它也是被文档化的注解。

欧博开户:教科书级解说,秒懂最详细Java的注解 第31张

其次,我们去在自界说注解中,标注上@Inherited注解。

欧博开户:教科书级解说,秒懂最详细Java的注解 第32张

演示@Inherited注解,我需要建立两个类,同时两个类中有一层的继续关系。如下:

欧博开户:教科书级解说,秒懂最详细Java的注解 第33张

我们在Person类中符号了@MyAnno注解,由于该注解被@Inherited注解修饰,我们就可以得出继续于Person类的Student类也同样被@MyAnno注解符号了,若是你要获取该注解的值的话,一定获取的也是父类上注解值的谁人"1"。

七、使用反射机制剖析注解

自界说注解

package com.mylifes1110.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @InterfaceName Sign
 * @Description 形貌需要执行的类名和方式名
 * @Author Ziph
 * @Date 2020/6/6
 * @Since 1.8
 */

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Sign {
    String methodName();

    String className();
}

Cat

package com.mylifes1110.java;

/**
 * @ClassName Cat
 * @Description 形貌一只猫的类
 * @Author Ziph
 * @Date 2020/6/6
 * @Since 1.8
 */

public class Cat {
    /*
     * @Description 形貌一只猫吃鱼的方式 
     * @Author Ziph
     * @Date 2020/6/6
     * @Param []
     * @return void
     */

    public void eat() {
        System.out.println("猫吃鱼");
    }
}

准备好,上述代码后,我们就可以最先编写使用反射手艺来剖析注解的测试类。如下:

首先,我们先通过反射来获取注解中的methodName和className参数。

package com.mylifes1110.java;

import com.mylifes1110.anno.Sign;

/**
 * @ClassName SignTest
 * @Description 要求建立cat工具并执行其类中eat方式
 * @Author Ziph
 * @Date 2020/6/6
 * @Since 1.8
 */

@Sign(className = "com.mylifes1110.java.Cat", methodName = "eat")
public class SignTest {
    public static void main(String[] args) {
        //获取该类的类工具
        Class<SignTest> signTestClass = SignTest.class;
        //获取类工具中的注解工具
        //原理实际上是在内存中天生了一个注解接口的子类实现工具
        Sign sign = signTestClass.getAnnotation(Sign.class);
        //挪用注解工具中界说的抽象方式(注解中的属性)来获取返回值
        String className = sign.className();
        String methodName = sign.methodName();
        System.out.println(className);
        System.out.println(methodName);
    }
}

此时的打印效果证实我们已经乐成获取到了该注解的两个参数。

欧博开户:教科书级解说,秒懂最详细Java的注解 第34张 image-20200606162810165

注重: 获取类工具中的注解工具时,其原理实际上是在内存中天生了一个注解接口的子类实现工具并返回的字符串内容。如下:

public class SignImpl implements Sign {
    public String methodName() {
        return "eat";
    }

    public String className() {
        return "com.mylifes1110.java.Cat";
    }
}

继续编写我们后面的代码,代码完整版如下:

完整版代码

package com.mylifes1110.java;

import com.mylifes1110.anno.Sign;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @ClassName SignTest
 * @Description 要求建立cat工具并执行其类中eat方式
 * @Author Ziph
 * @Date 2020/6/6
 * @Since 1.8
 */

@Sign(className = "com.mylifes1110.java.Cat", methodName = "eat")
public class SignTest {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        //获取该类的类工具
        Class<SignTest> signTestClass = SignTest.class;
        //获取类工具中的注解工具
        //原理实际上是在内存中天生了一个注解接口的子类实现工具
        Sign sign = signTestClass.getAnnotation(Sign.class);
        //挪用注解工具中界说的抽象方式(注解中的属性)来获取返回值
        String className = sign.className();
        String methodName = sign.methodName();
        //获取className名称的类工具
        Class<?> clazz = Class.forName(className);
        //建立工具
        Object o = clazz.newInstance();
        //获取methodName名称的方式工具
        Method method = clazz.getMethod(methodName);
        //执行该方式
        method.invoke(o);
    }
}

执行效果

执行后乐成的挪用了eat方式,并打印了猫吃鱼的效果,如下:

欧博开户:教科书级解说,秒懂最详细Java的注解 第35张

八、自界说注解改变JDBC工具类

首先,我们在使用JDBC的时刻是需要通过properties文件来获取设置JDBC的设置信息的,这次我们通过自界说注解来获取设置信息。实在使用注解并没有用设置文件好,然则我们需要领会这是怎么做的,获取方式也是鱼使用反射机制剖析注解,所谓“万变不离其宗”,它就是这样的。

自界说注解
package com.mylifes1110.java.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @InterfaceName DBInfo
 * @Description 给予注解声明周期为运行时并限制注解只能用在类上
 * @Author Ziph
 * @Date 2020/6/6
 * @Since 1.8
 */

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBInfo {
    String driver() default "com.mysql.jdbc.Driver";

    String url() default "jdbc:mysql://localhost:3306/temp?useUnicode=true&characterEncoding=utf8";

    String username() default "root"
;

    String password() default "123456";
}
数据库毗邻工具类

为了代码的健全我也在里面加了properties文件获取毗邻的方式。

package com.mylifes1110.java.utils;

import com.mylifes1110.java.anno.DBInfo;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
 * @ClassName DBUtils
 * @Description 数据库毗邻工具类
 * @Author Ziph
 * @Date 2020/6/6
 * @Since 1.8
 */

@DBInfo()
public class DBUtils {
    private static final Properties PROPERTIES = new Properties();
    private static String driver;
    private static String url;
    private static String username;
    private static String password;

    static {
        Class<DBUtils> dbUtilsClass = DBUtils.class;
        boolean annotationPresent = dbUtilsClass.isAnnotationPresent(DBInfo.class);
        if (annotationPresent) {
            /**
             * DBUilts类上有DBInfo注解,并获取该注解
             */

            DBInfo dbInfo = dbUtilsClass.getAnnotation(DBInfo.class);
//            System.out.println(dbInfo);
            driver = dbInfo.driver();
            url = dbInfo.url();
            username = dbInfo.username();
            password = dbInfo.password();
        } else {
            InputStream inputStream = DBUtils.class.getResourceAsStream("db.properties");
            try {
                PROPERTIES.load(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() {
        try {
            return DriverManager.getConnection(url, username, password);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return null;
    }

    public static void closeAll(Connection connection, Statement statement, ResultSet resultSet) {
        try {
            if (resultSet != null) {
                resultSet.close();
                resultSet = null;
            }

            if (statement != null) {
                statement.close();
                statement = null;
            }
            if (connection != null) {
                connection.close();
                connection = null;
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}
测试类
package com.mylifes1110.java.test;

import com.mylifes1110.java.utils.DBUtils;

import java.sql.Connection;

/**
 * @ClassName GetConnectionDemo
 * @Description 测试毗邻是否可以获取到
 * @Author Ziph
 * @Date 2020/6/6
 * @Since 1.8
 */

public class GetConnectionDemo {
    public static void main(String[] args) {
        Connection connection = DBUtils.getConnection();
        System.out.println(connection);
    }
}
测试效果

为了证实获取的毗邻是由注解的设置信息获取到的毗邻,我将properties文件中的所有设置信息删除后测试的。

欧博开户:教科书级解说,秒懂最详细Java的注解 第36张

九、自界说@MyTest注解实现单元测试

我不清晰小伙伴们是否领会,Junit单元测试。@Test是单元测试的测试方式上方修饰的注解。此注解的焦点原理也是由反射来实现的。若是有小伙伴不知道什么是单元测试或者对自界说@MyTest注解实现单元测试感兴趣的话,可以点进来看看哦!

,

Allbet

www.ordsports.com欢迎进入欧博平台(Allbet Gaming),欧博平台开放欧博(Allbet)开户、欧博(Allbet)代理开户、欧博(Allbet)电脑客户端、欧博(Allbet)APP下载等业务。

转载声明:本站发布文章及版权归原作者所有,转载本站文章请注明文章来源!

本文链接:https://www.shengyanshiting.com/post/883.html

网友评论

1条评论
  • 2020-07-28 00:10:04

    Allbet开户欢迎进入Allbet开户(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。其实够好了

最新评论

  • Allbet 10/21 说:

    Allbet手机版下载欢迎进入Allbet手机版下载(www.aLLbetgame.us):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。路过看看不走了

  • 环球UG网址 10/20 说:

    联博API接口www.326681.com采用以太坊区块链高度哈希值作为统计数据,联博以太坊统计数据开源、公平、无任何作弊可能性。联博统计免费提供API接口,支持多语言接入。满足了我看小说需求

  • 欧博亚洲客户端下载 10/19 说:

    AllbetAPP下载欢迎进入AllbetAPP下载(www.aLLbetgame.us):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。有才华的人

  • 环球UG注册 10/19 说:

    欧博官网手机欢迎进入欧博官网手机(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。还有更好的吗

  • 联博统计接口 10/19 说:

    欧博亚洲注册欢迎进入欧博亚洲注册(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。形容词都形容不出好

  • AllbetGmaing开户 10/18 说:

    联博统计www.326681.com采用以太坊区块链高度哈希值作为统计数据,联博以太坊统计数据开源、公平、无任何作弊可能性。联博统计免费提供API接口,支持多语言接入。这就是最高水平

  • AllbetGmaing开户 10/18 说:

    联博统计www.326681.com采用以太坊区块链高度哈希值作为统计数据,联博以太坊统计数据开源、公平、无任何作弊可能性。联博统计免费提供API接口,支持多语言接入。这就是最高水平

  • 环球UG官网 10/18 说:

    欧博亚洲客户端下载欢迎进入欧博亚洲客户端下载(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。人有多少啊