Java进阶16 单元测试&XML&注解

Java进阶16

一、单元测试

单元测试就是针对最小的功能单元编写测试代码,**Java程序最小的功能单元是方法,**因此,单原测试就是针对Java方法的测试,进而检查方法的正确性。简单理解就是测试代码的工具。

1、Junit

1.1 Junit引入

目前测试代码,只能在main方法中测试,如果某个方法的测试失败,其他方法测试会受到影响,而Junit解决了这个问题。

1.2 Junit优点
  • JUnit可以灵活的选择执行哪些测试方法,可以一键执行全部测试方法

  • 单元测试中的某个方法测试失败了,不影响其他方法的测试

  • 运行成功是绿色 ,运行失败是红色

1.3 Junit基本使用
  • 步骤

    ①手动导入jar包或在外部网络的情况下根据提示敲回车(add 'Junit4' to classpath)

    ②在需要测试的方法上,加入@Test注解

    ③运行绿色(正确),红色(错误)

  • 注意

    Junit测试的方法,必须是public的,且没有参数,没有返回值

二、XML

1、XML引入

XML全称EXtensible Markup Language,是一种可扩展的标记语言。【标记语言:通过标签来描述数据的一门语言】【可扩展:标签名可以自定义】xml文件可以为计算机程序配置参数和初始设置,使用xml文件的好处是可以让项目中使用的数据,灵活的加载和多变,实现解耦。

2、分类

2.1 Properties文件

用于一对一的存储

  • 键值对

  • username=root

  • password=123456

2.1 xml文件

常用于一对多存储

XML 复制代码
<?xml version="1.0" encoding="utf-8" ?>
<students>
    <!--第一个学生信息-->
    <student>
        <name>张三</name>
        <age>23</age>
    </student>
    <!--第二个学生信息-->
    <student>
        <name>李四</name>
        <age>24</age>
    </student>
</students>

3、优点

  • 作为软件的配置文件

  • 用于进行存储数据和传输数据(其内部格式更便于传输数据)

4、XML语法

4.1 语法规则
  • 创建

    创建一个XML类型的文件,要求文件的后缀必须使用xml。如hello_world.xml

  • 文档声明

    文档声明必须是第一行第一列

    XML 复制代码
    <?xml version="1.0" encoding="UTF-8" ?>
    • version:版本,该属性是必须存在

    • encoding:该属性不是必须的,指定打开当前的xml文件应该用什么字符编码表(一般都是UTF-8)

    • standalone:该属性不是必须的,描述XML文件是否依赖其他的XML文件,取值为yes/no

  • 标签规则

    • 必须存在一个根标签,有且只能有一个

    • 标签由一对尖括号和合法标识组成

    • 标签必须成对出现

      XML 复制代码
      <student></student>
    • 特殊的标签可以不成对,但是必须有结束标记

      XML 复制代码
      <address/>
    • 标签中可以定义属性,属性和标签名空格隔开,属性值必须用引号引起来

      XML 复制代码
      <studnet id="1"></studnet>
    • 标签需要正确的嵌套

      XML 复制代码
      <!--这是正确的嵌套--> 
      <student id="1"> 
          <name>张三</name>
      </student>
          
          
      <!--这是错误的嵌套--> 
      <student id="1">
          <name>张三
          </student>
      </name>
  • 细节

    • XML文件中可以定义注释信息

      XML 复制代码
      <!--这是一条注释信息-->
    • XML文件中可以存在以下特殊字符

      XML 复制代码
      &lt    <   小于
      &gt    >   大于
      &amp   &   和号
      &apos  '   单引号
      &quot  "   引号
    • XML文件中可以存在CDATA区

      XML 复制代码
      <![CDATA[...内容...]]>
4.2 Demo

需求:编写一个城市对应区的xml文件【城市city;区域area】

XML 复制代码
<?xml version="1.0" encoding="utf-8" ?>
<citys>
    <city name="北京市">
        <area>东城区</area>
        <area>西城区</area>
        <area>朝阳区</area>
        <area>海淀区</area>
        <area>昌平区</area>
    </city>
</citys>

5、XML约束(了解)

XML约束用来限定xml文件中可使用的标签以及属性,约束文件以后不需要我们自己写,了解即可。有DTD约束和Schema约束

5.1 DTD约束
① 编写DTD约束
  • 步骤

    1.创建一个后缀名为.dtd的文件

    2.看xml文件中使用了哪些元素<!ELEMENT>可以定义元素

    3.判断元素是简单元素还是复杂元素

    【简单元素】没有子元素

    【复杂元素】有子元素的元素

  • 代码实现

    XML 复制代码
    <!--这是一个dtd文件  persondtd.dtd-->
    <!ELEMENT persons (person)>
    <!ELEMENT person (name,age)>
    <!ELEMENT name (#PCDATA)>
    <!ELEMENT age (#PCDATA)>
② 引入DTD约束
  • 在xml文件内部直接引入

    复制代码
    <!DOCTYPE 根元素名称 [ dtd文件内容 ]>
    XML 复制代码
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE persons [
            <!ELEMENT persons (person)>
            <!ELEMENT person (name,age)>
            <!ELEMENT name (#PCDATA)>
            <!ELEMENT age (#PCDATA)>
            ]>
    ​
    <persons>
        <person>
            <name>张三</name>
            <age>23</age>
        </person>
    ​
    </persons>
  • 引入本地dtd

    复制代码
    <!DOCTYPE 根元素名称 SYSTEM 'DTD文件的路径'>
    XML 复制代码
    <!--在person1.xml文件中引入persondtd.dtd约束-->
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE persons SYSTEM 'persondtd.dtd'>
    ​
    <persons>
        <person>
            <name>张三</name>
            <age>23</age>
        </person>
    ​
    </persons>
  • 引入网络dtd

    复制代码
    <!DOCTYPE 根元素的名称 PUBLIC "DTD文件名称" "DTD文档的URL">
    XML 复制代码
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE persons PUBLIC "dtd文件的名称" "dtd文档的URL">
    ​
    <persons>
        <person>
            <name>张三</name>
            <age>23</age>
        </person>
    ​
    </persons>
5.2 Schema约束
①编写schema约束
  • 步骤

    1.创建一个文件,这个文件的后缀名为.xsd

    2.定义文档声明

    3.schema文件的根标签为<schema>

    4.在<scheam>中定义如下属性:

    • targetNamespace = 唯一的url地址,指定当前这个schema文件的名称空间(理解起个名字,顺便打广告)

    • elementFormDefault="qualified",表示当前schema文件是一个质量良好的文件

    5.通过element定义元素

    6.判断当前元素是简单元素还是复杂元素

  • 代码实现

    XML 复制代码
    <?xml version="1.0" encoding="UTF-8" ?>
    ​
    <schema xmlns="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://www.itheima.com"
            elementFormDefault="qualified">
        <element name="students">
            <complexType>
                <sequence>
                    <element name="student" maxOccurs="unbounded">
                         <complexType>
                             <sequence>
                                 <element name="name" type="string"></element>
                                 <element name="age" type="int"></element>
                             </sequence>
                             <attribute name="id" use="required"/>
                         </complexType>
                    </element>
                </sequence>
            </complexType>
        </element>
    </schema>
②引入schema约束
XML 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
​
<!--这里xsi只是因为需要引入多个约束怕属性重名所以取的别名-->
​
​
<students xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns="http://www.itheima.com"
          xsi:schemaLocation="http://www.itheima.com students.xsd">
    <student id="1">
        <name>张三</name>
        <age>23</age>
    </student>
​
    <student id="2">
        <name>李四</name>
        <age>24</age>
    </student>
​
</students>
5.3 Schema和dtd的区别
  • schema约束文件也是一个xml文件,符合xml的语法,这个文件的后缀名.xsd。Schema文件用来约束一个xml文件,同时它自己也被其他文件约束着

  • 一个xml中可以引用多个schema约束文件 ,多个schema使用名称空间区分(名称空间类似于java包名)

  • dtd里面元素类型的取值比较单一常见的是PCDATA类型,但是在schema里面可以支持很多个数据类型

  • schema 语法更加的复杂

6、XML解析

解析方式有两种:SAX解析和DOM解析

SAX解析 DOM解析
解析方式 不会把整体的xml文件都加载到内存中,而是从上往下逐行进行扫描 会把整体的xml文件都加载到内存
优点 因为逐行解析,无需将整体的xml文件都加载到内存,所以可以解析较大的xml文件 可以读取,可以添加,可以删除,可以做任何事情
缺点 只能读取,不能添加,不能删除 需要xml文件全部加载到内存,所以不能解析非常大的xml文件
6.1 DOM解析
6.1.1 解析文档对象模型
6.1.2 常见解析工具
名称 说明
JAXP SUN公司提供的一套XML解析的API
JDOM JDOM是一个开源项目,它基于树型结构,利用纯JAVA的技术对XML文档实现解析、生成、序列化以及多种操作
Dom4j 是JDOM的升级品,用来读写XML文件的。具有性能优异,功能强大和极其易使用的特点,它的性能超过sun公司官方的dom技术,同时它也是一个开放源代码的软件,Hibernate也用它来读写配置文件
jsoup 功能强大DOM方式的XML解析开发包,尤其对HTML解析更加方便
6.1.3 准备动作

①导入jar包

②获取Document对象

java 复制代码
SAXReader reader = new SAXReader();
Document document = reader.read(url);
System.out.println(document);
6.1.4 方法
方法 说明
Element getRootElement() 获取根元素对象
方法 说明
List<Element> elements() 得到当前元素下所有子元素
List<Element> elements(String name) 得到当前元素下指定名字的子元素返回集合
Element element(String name) 得到当前元素下指定名字的子元素,如果有很多名字相同的返回第一个
String getName() 得到元素名字
String attributeValue(String name) 通过属性名直接得到属性值
String elementText(子元素名) 得到指定名称的子元素的文本
String getText() 得到文本
6.1.5 Demo(解析xml信息存入集合)
java 复制代码
public class ParseXml {
    public static void main(String[] args) throws DocumentException {
        //准备集合
        ArrayList<Student> list = new ArrayList<>();
        SAXReader reader = new SAXReader();
        Document document = reader.read("day16\\src\\com\\itheima\\xml\\students.xml");
        
        //1、获取根标签
        Element rootElement = document.getRootElement();
        //2、获取根标签下的所有子标签
        List<Element> elements = rootElement.elements();
        //3、遍历集合
        for (Element element : elements) {
            //4、获取标签属性
            String id = element.attributeValue("id");
            //5、获取name标签的值
            String name = element.element("name").getText();
            //6、获取age标签的值
            String age = element.element("age").getText();
            //7、封装为Student学生对象
            Student stu = new Student(id,name,Integer.parseInt(age));
            //8、添加到集合
            list.add(stu);
        }
        list.forEach(System.out::println);
    }
}

三、注解

Annotation标识注解,是JDK1.5的新特性,作用是对程序进行标注。其实可以对照注释理解(注释是给人看的,而注解是给编译器或虚拟机看的),通过注解可以给类增加一些额外的信息,让编译器或jvm可以根据注解来完成对应的功能

1、JDK常见注解

  • @Override:表示方法的重写

  • @Deprecated:表示修饰的方法已过时

  • @SuppressWarinings("all"):压制警告

除此之外,还需要掌握第三方框架中提供的注解:比如Junit中

  • @Test表示运行测试方法

  • @Before表示在Test之前运行,进行初始化

  • @After表示在Test之后运行,进行收尾

2、自定义注解(了解)

自定义注解单独存在没有意义 ,一般会跟反射结合起来使用

2.1 格式
java 复制代码
public @interface 注解名称 {
    public 属性类型 属性名 () default 默认值 ;
}
​
public @interface Anno {
    String show() default "show..." ;
}

属性类型可以是:基本数据类型、String、Class、注解、枚举、以及上述类型的一维数组

java 复制代码
public @interface MyAnno {
    public static final int num1 = 100;
    public static final String num2 = "abc";
    public static final MyAnno num3 = null;
    public static final Class num4 = String.class;
    public static final int[] num5 = {};
​
    public abstract String show1() default "show1";
    public abstract int show2() default 132;
    public abstract MyAnno2 show3() default @MyAnno2;
    public abstract Class show4() default String.class;
    public abstract int[] show5() default {1, 2, 3};
}
java 复制代码
public @interface MyAnno {
    int num1 = 100;
    String num2 = "abc";
    MyAnno num3 = null;
    Class num4 = String.class;
    int[] num5 = {};
​
    String show1() default "123";
    int show2() default 132;
    MyAnno2 show3() default @MyAnno2;
    Class show4() default String.class;
    int[] show5() default {1, 2, 3};
}

注意事项:

  • 在使用注解时,如果注解的属性没有给出默认值,需要手动给出;如@Anno(name="张三")

  • 如果数组中只有一个属性值,在使用时{}是可以省略的

  • 定义注解中,如果有多个属性没有赋值,使用时需要全部赋值

  • 定义注解中如果只有一个属性名称为value,没有赋值,使用时直接给出值,不需要写属性名。如@Anno("要给value赋的值")

3、元注解(了解)

元注解就是描述注解的注解

元注解名 说明
@Target 指定了注解能在哪里使用
@Retention 可以理解为保留时间(生命周期)
3.1 Target注解

用来标识注解使用的位置,如果没有使用该注解标识,则自定义的注解可以使用在任意位置,可使用的值定义在ElementType枚举类中,常用值如下:

  • TYPE,类,接口

  • FIELD,成员变量(很少用)

  • METHOD,成员方法

  • PARAMETER,方法参数

  • CONSTRUCTOR,构造方法

  • LOCAL_VARIABLE,局部变量

3.2 Retention注解

用来标识注解的生命周期(有效范围),可使用的值定义在RetentionPolicy枚举类中,常用值如下:

  • SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在

  • CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值

  • RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段

4、案例(自定义注解)

  • 需求:自定义一个注解@MyAnno,用于指定类的方法上,如果某一个类的方法上使用了该注解,就执行该方法
  • 实现步骤:

    1.自定义一个注解MyAnno,并在类中的某几个方法上加注解

    2.在测试类中,获取注解所在的类的Class对象

    3.获取类中所有的方法对象

    4.遍历每一个方法对象,判断是否有对应的注解

java 复制代码
//自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
}
java 复制代码
//Test类
public class MethodTest {
    @MyAnno
    public void show1(){
        System.out.println("show1...");
    }
​
   @MyAnno
    public void show2(){
        System.out.println("show2...");
    }
​
    public void show3(){
        System.out.println("show3...");
    }
}
java 复制代码
public class ReflectTest {
    /*
         简易的测试框架,通过反射操作字节码对象,执行需求的逻辑
     */
    public static void main(String[] args) throws Exception{
        //1、通过反射获取字节码文件对象
        Class<MethodTest> methodTestClass = MethodTest.class;
        //2、创建对象
        MethodTest mt = methodTestClass.getConstructor().newInstance();
​
        //3、通过反射获取这个类里面所有的方法对象
        Method[] methods = methodTestClass.getMethods();
        //4、遍历数组,得到每一个方法对象
        for (Method method : methods) {
            //核心:判断这个方法头上有没有注解
            if(method.isAnnotationPresent(MyAnno.class)){
                //执行方法
                method.invoke(mt);
            }
        }
    }
}
相关推荐
m0_7482451719 分钟前
Web第一次作业
java
小码的头发丝、19 分钟前
Java进阶学习笔记|面向对象
java·笔记·学习
m0_5485147722 分钟前
前端Pako.js 压缩解压库 与 Java 的 zlib 压缩与解压 的互通实现
java·前端·javascript
坊钰1 小时前
【Java 数据结构】移除链表元素
java·开发语言·数据结构·学习·链表
chenziang11 小时前
leetcode hot100 LRU缓存
java·开发语言
Purple Coder1 小时前
第6章 图论
笔记
会说法语的猪1 小时前
springboot实现图片上传、下载功能
java·spring boot·后端
码农老起1 小时前
IntelliJ IDEA 基本使用教程及Spring Boot项目搭建实战
java·ide·intellij-idea
m0_748239831 小时前
基于web的音乐网站(Java+SpringBoot+Mysql)
java·前端·spring boot