java底子进阶——log日志、类加载器、XML、单位测试、注解、罗列类 ...

打印 上一主题 下一主题

主题 536|帖子 536|积分 1608

前言

  这篇内容重要掌握的就是logback使用、明白类加载器、XML文件的编写,XML文档束缚schema,用Dom4j解析XML文档,Xpath检索XML文档,完整使用Junit单位测试框架常用部分,注解的界说和使用,罗列类的界说和开发应用。
  一、log日志

log日志类似输出语句,可以用来输出步伐的信息,但是log日志更加好用。
1.输出语句的弊端


2. log日志的优点

   可以将系统实行的信息选择性的记录到指定的位置(控制台、文件中、数据库中)。
  可以随时以开关的形式控制是否记录日志,无需修改源代码。
    日志技能的具体优势
  

  3.日志框架体系

日志框架需要日志规范的要求实现,日志规范大多是一些接口,提供给实现框架去计划的。常见的规范有:Commons Logging、SimpleLoggingFacadeforJava。
志的实现框架有,Log4J、Logback(我们重点学习的,其他的都大同小异)


4.日志框架LogBack 

(1)概述

   Logback是基于slf4j的日志规范实现的框架,性能比之前使用的log4j要好。
  官方网站:Logback Home
  
  Logback重要分为三个技能模块:
   logback-core:该模块为其他两个模块提供底子代码,必须有。
   logback-classic:完整实现了slf4j APl的模块。
   logback-access模块与Tomcat和Jetty等Servlet容器集成,以提供HTTP访问日志功能
   (2)配置

   1.创建一个maven项目,在pom文件将下面的依赖坐标导入项目
  1.         <dependency>
  2.             <groupId>ch.qos.logback</groupId>
  3.             <artifactId>logback-classic</artifactId>
  4.             <version>1.2.3</version>
  5.         </dependency>
复制代码
 刷新maven自动导入下面三个jar包
  

  2. 将Logback的焦点配置文件logback.xml直接拷贝到maven项目的resources目录下
  

  logback.xml内容如下:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <configuration>
  3.     <!--
  4.             CONSOLE :表示当前的日志信息是可以输出到控制台的。
  5.             -->
  6.     <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
  7.         <!--输出流对象 默认 System.out 改为 System.err-->
  8.         <target>System.out</target>
  9.         <encoder>
  10.             <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度
  11.                     %msg:日志消息,%n是换行符-->
  12.             <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level]  %c [%thread] : %msg%n</pattern>
  13.         </encoder>
  14.     </appender>
  15.     <!-- File是输出的方向通向文件的 -->
  16.     <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  17.         <encoder>
  18.             <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
  19.             <charset>utf-8</charset>
  20.         </encoder>
  21.         <!--日志输出路径-->
  22.         <file>C:/code/itpzh-data.log</file>
  23.         <!--指定日志文件拆分和压缩规则-->
  24.         <rollingPolicy
  25.                 class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
  26.             <!--通过指定压缩文件名称,来确定分割文件方式-->
  27.             <fileNamePattern>C:/code/itpzh-data2-%d{yyyy-MMdd}.log%i.gz</fileNamePattern>
  28.             <!--文件拆分大小-->
  29.             <maxFileSize>1MB</maxFileSize>
  30.         </rollingPolicy>
  31.     </appender>
  32.     <!--
  33.             level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF
  34.             , 默认debug
  35.     <root>可以包含零个或多个<appender-ref>元素,标识这个输出位置将会被本日志级别控制。
  36.             -->
  37.     <root level="info">
  38.         <appender-ref ref="CONSOLE"/>
  39.         <appender-ref ref="FILE" />
  40.     </root>
  41. </configuration>
复制代码
(3)入门步伐

   A.步骤

  1.获取日志的对象。
  1. private final static Logger LOGGER = LoggerFactory.getLogger("类对象");
复制代码
注意:这个对象要全局共享唯一(static final修饰)
             这个Logger一定要是org.slf4j.Logger这个第三方包下的
  2.用日志对象的方法记录系统的日志信息。
   B.入门实例代码

  1. import org.slf4j.Logger;
  2. import org.slf4j.LoggerFactory;
  3. import java.util.Scanner;
  4. public class LoggerDemo1 {
  5.     //获取一个共享的唯一的log日志对象
  6.     private final static Logger LOGGER = LoggerFactory.getLogger(LoggerDemo1.class);
  7.     public static void main(String[] args) {
  8.         //获取用户登录的日志
  9.         Scanner sr = new Scanner(System.in);
  10.         while (true) {
  11.             System.out.println("请输入用户名");
  12.             String username = sr.next();
  13.             System.out.println("请输入密码");
  14.             String password = sr.next();
  15.             if ("张三".equals(username) && "12345".equals(password)) {
  16.                 LOGGER.info("用户{}登录成功,密码为{}", username, password);
  17.                 break;
  18.             } else {
  19.                 LOGGER.info("用户{}登录失败", username);
  20.             }
  21.         }
  22.     }
  23. }
复制代码
  运行完,LOGGER.info的内容不仅体现在控制台,而且还被保存到文件内里
  由于配置文件appender标签内容有配置,后面会说 
  (4)配置文件logback.xml解说

Logback日志系统的特性都是通过焦点配置文件logback.xml控制的。
   Loaback日志输出位置、格式设置:
  1.通过logback.xml中的<appender>标签可以设置输出位置和日志信息的详细格式。
  2.通常可以设置2个日志输出位置:一个是控制台、一个是系统文件中
  

     下面的<appender>标签内的各种标签解说
  <appender>标签的属性name=CONSOLE时体现输出到控制台
  class体现输出到控制台的功能由ch.qos.logback.core.ConsoleAppender这个类来实现
  <target>标签体现System.out以标准输出流的形式输出到控制台上面
  <encoder>和<pattern>标签规定输出内容的格式,%d{yyyy-MM-dd HH:mm:ss.SSS}体现按格式输出年代日 时分秒        [%-5level]表留五个空格的长度输出日志的等级        %c体现当前操作的类
  %thread体现当前所在的线程,好比main线程     %msg体现输出的信息
  

     下面讲解<root>标签内的属性和附属标签
  <root>标签控制哪几个<appender>标签能否生效的,内里用<appender-ref/>标签标记要生效的<appender>标签。
  <root>标签的属性level用来设置打印级别,一共7个,All体现<root>标签所包含的<appender-ref/>标签全部生效,OFF体现全部不生效。
  

  (5)日志级别

   作用:
  如果系统上线后只想记录一些错误的日志信息大概不想记录日志了,怎么办?
  可以通过设置日志的输出级别来控制哪些日志信息输出大概不输出。
   

  解说:日志级别是可以通过日志对象的.level方法去设置的,不设置的话默认是继承日志的顶级父类 root的级别debug。
  当<root>标签的level属性设置为WARN时,日志对象如果日志级别为TRACE,DEBUG,INFO就不输出日志。
  二、类加载器

1.作用

   负责将.class文件(存储的物理文件)加载在到内存中
  

  2.类加载的完整过程

 (1)类加载时机

(简单明白:字节码文件什么时间会被加载到内存中?)
   有以下的几种情况:
  

  • 创建类的实例(对象)
  • 调用类的类方法
  • 访问类大概接口的类变量,大概为该类变量赋值
  • 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
  • 初始化某个类的子类
  • 直接使用java.exe命令来运行某个主类
  总结而言:用到了就加载,不消不加载
  (2)类加载过程  

   类加载分为5个阶段
  加载,验证,准备,解析,初始化。
  其中验证,准备,解析归为链接阶段
  

   加载

   就是,将字节码文件通过IO流读取到JVM的方法区,并同时在堆中生成Class对象。
  

  • 通过包名 + 类名,获取这个类,准备用流进行传输
  • 在这个类加载到内存中
  • 加载完毕创建一个class对象
  

  注意:创建的class对象的变量类型如果是引用类型,就用符号代替
  链接 

   A.验证

  确保Class文件字节流中包含的信息符合当前假造机的要求,并且不会危害假造机自身安全
  (文件中的信息是否符合假造机规范有没有安全隐患)
  

    B.准备

  负责为类的类变量(被static修饰的变量)分配内存,并设置默认初始化值
  (初始化静态变量)
  

  
    C.解析

  将类的二进制数据流中的符号引用替换为直接引用
  (本类中如果用到了其他类,此时就需要找到对应的类)
  这里的符号引用,意思是,在类加载的时间将一个类的字节码文件以二进制数据流输入JVM,该类的成员变量的类型如果是像String类型这种引用类型,但是在加载的时间,String从哪里来那里去都不知道,于是先用符号代替String,这就是符号引用
  

  初始化

   根据步伐员通过步伐订定的主观计划去初始化类变量和其他资源
  (静态变量赋值以及初始化其他资源)
  

   3.类加载器分类

   (1)分类

  

  • Bootstrap class loader:假造机的内置类加载器,通常体现为null ,并且没有父级类加载器
  • Platform class loader:平台类加载器,负责加载JDK中一些特别的模块
  • System class loader:系统类加载器,负责加载用户类路径上所指定的类库
  • 自界说类加载器
    (2)类加载器的继承关系(逻辑上的继承,看后面的双亲委派模子)

  自界说加载器的父加载器为System
  System的父加载器为Platform
  Platform的父加载器为Bootstrap
    (3)代码演示证明

  1. public class ClassLoaderDemo1 {
  2.     public static void main(String[] args) {
  3.         //获取系统类加载器
  4.         ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
  5.         //获取系统类加载器的父加载器 --- 平台类加载器
  6.         ClassLoader classLoader1 = systemClassLoader.getParent();
  7.         //获取平台类加载器的父加载器 --- 启动类加载器
  8.         ClassLoader classLoader2 = classLoader1.getParent();
  9.         System.out.println("系统类加载器" + systemClassLoader);
  10.         System.out.println("平台类加载器" + classLoader1);
  11.         System.out.println("启动类加载器" + classLoader2);
  12.     }
  13. }
复制代码
 运行结果

  4. 双亲委派模子

   如果一个类加载器收到了类加载请求,它并不会本身先去加载,而是把这个请求委托给父类的加载器去实行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求终极将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试本身去加载,这就是双亲委派模式
  

  5.ClassLoader 中的两个方法

方法名说明
public static ClassLoader getSystemClassLoader()获取系统类加载器
public InputStream getResourceAsStream(String name)加载某一个资源文件
   实例代码
  1. public class ClassLoaderDemo2 {
  2.     public static void main(String[] args) throws IOException {
  3.         //获取系统类加载器
  4.         ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
  5.         //利用加载器去加载一个指定的文件
  6.         //参数:文件的路径(放在maven项目的resources目录下,默认去那里加载)
  7.         //返回值:字节流。
  8.         InputStream is = systemClassLoader.getResourceAsStream("prop.properties");
  9.         Properties properties = new Properties();
  10.         properties.load(is);
  11.         System.out.println(properties);
  12.         is.close();
  13.     }
  14. }
复制代码
三、XML

1.配置文件

   XML文件一般作为配置文件使用,那么什么是配置文件?
  配置文件就是,用来保存步伐在运行时需要的一些参数。好比说idea的配置文件,当我们第一次使用idea的时间,我们配置idea的主题,字体巨细等等,这些参数会被保存在idea的配置文件内里,当我们再次打开idea的时间,idea会从配置文件中加载这些参数,就不消我们重新配置idea主题什么的了。
  常见的配置文件有什么?
  有.txt文件,有.properties文件,有.xml文件
  三种配置文件的优缺点?
  txt文件只记录参数的值,太初略
  properties文件以键值对的形式记录参数,较为详细
  

  但是对于复杂的多用户的配置文件,就不顺应,选择使用xml文件
  

  TXT文件:没有优点,缺点是倒霉于阅读
  properties文件:优点就是键值对形式易于阅读,缺点就是无法配置一组一组的数据。
  XML文件:优点是易于阅读,可以配置成组出现的数据
  以后配置文件怎么选择?
  数据量较少,一个键只对应一个值,使用properties
  数据量较多,使用xml
  2.XML概述

   XML的全称为(EXtensible Markup Language),是一种可扩展的标记语言标记语言: 通过标签来描述数据的一门语言(标签偶然我们也将其称之为元素)可扩展:标签的名字是可以自界说的,XML文件是由很多标签构成的,而标签名是可以自界说的
  

  • 作用

    • 用于进行存储数据和传输数据
    • 作为软件的配置文件

  • 作为配置文件的优势

    • 可读性好
    • 可维护性高

  

  3.XML的基本语法

   (1)XML文件的定名和位置

  XML文件要放在src目录下,大概放在maven项目下面的resources目录下面
  
(2)标签(元素)规则 


  (3)XML其他构成 

  

  (4)示例

  

  4.XML文档束缚

(1)什么是文档束缚?

   
 于是需要文档束缚来用来限定xml文件中的标签以及属性应该怎么写。以此强制束缚步伐员必须按照文档束缚的规定来编写xml文件。
  (2)束缚分类

   DTD
  schema
  (3)DTD束缚

   DTD束缚编写

  A.步骤
  

  • 创建一个文件,这个文件的后缀名为.dtd
  • 看xml文件中使用了哪些元素
    <!ELEMENT> 可以界说元素
  • 判定元素是简单元素照旧复杂元素
    简单元素:没有子元素。复杂元素:有子元素的元素;
  • 简单元素修饰词
    ​ EMPTY: 体现标签体为空
    ​ ANY: 体现标签体可以为空也可以不为空
    ​ PCDATA: 体现该元素的内容部分为字符串
  • 复杂元素修饰词​                                                                                                                   直接写子元素名称. 多个子元素可以使用","大概"|"隔开;​ ","体现界说子元素的顺序 ; "|": 体现子元素只能出现任意一个​ "?"零次或一次, "+"一次或多次, "*"零次或多次;如果不写则体现出现一次
  • 元素的属性的界说
    格式
    界说一个属性的格式为:<!ATTLIST 元素名称 属性名称 属性的类型 属性的束缚>属性的类型:​ CDATA类型:普通的字符串
    属性的束缚:
    ​ // #REQUIRED: 必须的​ // #IMPLIED: 属性不是必需的​ // #FIXED value:属性值是固定的
  

  B.代码
  简单入门
  1. <!ELEMENT persons (person)>
  2. <!ELEMENT person (name,age)>
  3. <!ELEMENT name (#PCDATA)>
  4. <!ELEMENT age (#PCDATA)>
复制代码
 复杂
  1. <!ELEMENT persons (person+)>
  2. <!ELEMENT person (name,age)>
  3. <!ELEMENT name (#PCDATA)>
  4. <!ELEMENT age (#PCDATA)>
  5. <!ATTLIST person id CDATA #REQUIRED>
复制代码

    DTD束缚引入

  三种引入方式
  

    简单入门代码

  1. // 这是persondtd.dtd文件中的内容,已经提前写好<!ELEMENT persons (person)>
  2. <!ELEMENT person (name,age)>
  3. <!ELEMENT name (#PCDATA)>
  4. <!ELEMENT age (#PCDATA)>// 在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>
复制代码
复杂代码 

  1. //dtd代码<!ELEMENT persons (person+)>
  2. <!ELEMENT person (name,age)>
  3. <!ELEMENT name (#PCDATA)>
  4. <!ELEMENT age (#PCDATA)>
  5. <!ATTLIST person id CDATA #REQUIRED>//xml代码<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE persons SYSTEM 'persondtd.dtd'><persons>    <person id="001">        <name>张三</name>        <age>23</age>    </person>    <person id = "002">        <name>张三</name>        <age>23</age>    </person></persons>
复制代码
 (4)schema束缚

   schema和dtd的区别

  

  • schema束缚文件也是一个xml文件,符合xml的语法,这个文件的后缀名.xsd
  • 一个xml中可以引用多个schema束缚文件,多个schema使用名称空间区分(名称空间类似于java包名)
  • dtd内里元素类型的取值比力单一常见的是PCDATA类型,但是在schema内里可以支持很多个数据类型
  • schema 语法更加的复杂
  
    schema束缚编写

  A.步骤 
  1,创建一个文件,这个文件的后缀名为.xsd。
  2,界说文档声明(跟xml文件第一行一样)
  3,schema文件的根标签为: <schema>
  4,在<schema>中界说属性:​ xmlns=http://www.w3.org/2001/XMLSchema
  5,在<schema>中界说属性 :​ targetNamespace =唯一的url地址,指定当前这个schema文件的名称空间。
  6,在<schema>中界说属性 :​ elementFormDefault="qualified“,体现当前schema文件是一个质量良好的文件。直接复制用就行
  7,通过element界说元素
  8,判定当前元素是简单元素照旧复杂元素
  

  代码
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <schema xmlns="http://www.w3.org/2001/XMLSchema"
  3.         targetNamespace="http://www.example.org/b"
  4.         elementFormDefault="qualified">
  5.     <element name="persons">
  6.         <complexType>
  7.             <sequence maxOccurs="unbounded">
  8.                 <element name="person">
  9.                     <complexType>
  10.                         <sequence>
  11.                             <element name="name" type="string"/>
  12.                             <element name="age" type="int"/>
  13.                         </sequence>
  14.                     </complexType>
  15.                 </element>
  16.             </sequence>
  17.         </complexType>
  18.     </element>
  19. </schema>
复制代码
   schema束缚引入

  直接在xml文件的第二行,先输入<,idea会弹出提示框,选择目标的xsd
  选择后idea直接导入束缚
  


     入门代码

  1. //xsd代码<?xml version="1.0" encoding="UTF-8" ?>
  2. <schema xmlns="http://www.w3.org/2001/XMLSchema"
  3.         targetNamespace="http://www.example.org/b"
  4.         elementFormDefault="qualified">
  5.     <element name="persons">
  6.         <complexType>
  7.             <sequence maxOccurs="unbounded">
  8.                 <element name="person">
  9.                     <complexType>
  10.                         <sequence>
  11.                             <element name="name" type="string"/>
  12.                             <element name="age" type="int"/>
  13.                         </sequence>
  14.                     </complexType>
  15.                 </element>
  16.             </sequence>
  17.         </complexType>
  18.     </element>
  19. </schema>//xml代码<?xml version="1.0" encoding="UTF-8" ?><persons xmlns="http://www.example.org/b">    <person>        <name>张三</name>        <age>18</age>    </person>    <person>        <name>张三</name>        <age>18</age>    </person>    <person>        <name>张三</name>        <age>18</age>    </person></persons>
复制代码
 5.XML文件解析

   XML的数据的作用是什么,终极需要怎么处理处罚?
  存储数据、做配置信息、进行数据传输, 
  终极需要被步伐进行读取,解析内里的信息。
  有几种解析方式?
  SAX(一般不消)和DOM
  SAX和DOM的优缺点
  SAX:不会把整体的xml文件都加载到内存,而是从上往下逐行进行扫描。
缺点:只能读取,不能添加,不能删除。
优点:由于他是逐行扫描不需要把整体的xml文件都加载到内存,所以他可以解析比力大的xml文件。
  DOM:会把整体的xml文件都加载到内存。
会把这个整天在内存中形成一个树形布局,我们可以通过这个树形布局去解析xml文件。
优点:可以读取,可以添加,可以删除,可以做任何事变。
缺点:需要xml文件全部加载到内存,所以不能解析非常大的xml文件。
  (1)Dom解析的文档对象模子(一层一层解析的过程)


 (2)Dom常见的解析工具


 6.Dom4j解析XML

(1)快速入门

  1. public class Dom4jDemo1 {
  2.     public static void main(String[] args) throws DocumentException {
  3.         //1.创建解析器对象
  4.         SAXReader saxReader = new SAXReader();
  5.         //2.利用解析器去读取XML文件,并返回文件对象
  6.         File file = new File("src\\main\\resources\\a.xml");
  7.         Document document = saxReader.read(file);
  8.         //拿到了document表示我已经拿到了xml文件的整体
  9.         //3.打印
  10.         System.out.println(document);
  11.         //下面一层一层的扒开获取里面的内容即可
  12.     }
  13. }
复制代码
 (2)成员方法

   

  

   Element类

  (3)终极示例

   需求:
          将下面的XML文件的几个人的信息保存到内存中
  建议:创建一个Person类来存储人物信息
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <persons>
  3.     <person id="1">
  4.         <name>张三</name>
  5.         <age>18</age>
  6.     </person>
  7.     <person id="2">
  8.         <name>李四</name>
  9.         <age>20</age>
  10.     </person>
  11.     <person id="3">
  12.         <name>张三</name>
  13.         <age>21</age>
  14.     </person>
  15. </persons>
复制代码
   创建一个Person类
  1. public class Person {
  2.     private int id;
  3.     private String name;
  4.     private int age;
  5.     public Person(int id, String name, int age) {
  6.         this.id = id;
  7.         this.name = name;
  8.         this.age = age;
  9.     }
  10.     @Override
  11.     public String toString() {
  12.         return "Person{" +
  13.                 "id=" + id +
  14.                 ", name='" + name + '\'' +
  15.                 ", age=" + age +
  16.                 '}';
  17.     }
  18. }
复制代码
   正文代码
  1. public class Dom4jDemo2 {
  2.     public static void main(String[] args) throws DocumentException {
  3.         //1.创建解析器对象
  4.         SAXReader saxReader = new SAXReader();
  5.         //2.利用解析器去读取XML文件,并返回文件对象
  6.         File file = new File("src\\main\\resources\\a.xml");
  7.         Document document = saxReader.read(file);
  8.         //拿到了document表示我已经拿到了xml文件的整体
  9.         //创建一个集合来存储人物的信息
  10.         ArrayList<Person> list = new ArrayList<>();
  11.         //下面一层一层的扒开获取里面的内容即可
  12.         //获取根元素
  13.         Element rootElement = document.getRootElement();
  14.         //获取根元素下的所有person元素
  15.         List<Element> elements = rootElement.elements("person");
  16.         for (Element element : elements) {
  17.             //获取子元素的id属性
  18.             Attribute id = element.attribute("id");
  19.             String idValue = id.getValue();
  20.             //获取子元素的name和age
  21.             String nameValue = element.element("name").getText();
  22.             String ageValue = element.element("age").getText();
  23.             Person person = new Person(Integer.parseInt(idValue), nameValue, Integer.parseInt(ageValue));
  24.             list.add(person);
  25.         }
  26.         list.stream().forEach(System.out::println);
  27.     }
  28. }
复制代码
7.XML检索技能Xpath

   如果需要从XML文件中检索需要的某个信息(如name)怎么解决?
  Dom4j需要进行文件的全部解析,然后再寻找数据。
  Xpath技能更加适合做信息检索。
     XPath在解析XML文档方面提供了一独树一帜的路径头脑,更加优雅,高效。
  XPath使用路径表达式来定位XML文档中的元素节点或属性节点
  /元素/子元素/孙元素
  //子元素//孙元素
   (1)使用步骤

   1.导入jar包(dom4j和jaxen-1.1.2.jar),Xpath技能依赖Dom4j技能
  2.通过dom4j的SAXReader解析器获取Document对象
  3.利用XPath提供的API,结合XPath的语法完成选取XML文档元素节点进行解析操作。
  4.Document中与Xpath相干的API如下:
  

  (2)路径表达式

   绝对路径

  

  相对路径

  
 全文搜刮


  

  属性查找

  

  (3)快速入门

   需求:
          利用Xpath检索技能解析XML中的name元素,XML文件内容如下
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <persons>
  3.     <person id="1">
  4.         <name>张三</name>
  5.         <age>18</age>
  6.     </person>
  7.     <person id="2">
  8.         <name>李四</name>
  9.         <age>20</age>
  10.     </person>
  11.     <person id="3">
  12.         <name>王五</name>
  13.         <age>21</age>
  14.     </person>
  15.     <name>基尼太妹</name>
  16. </persons>
复制代码
   代码
  1. public class XpathDemo {
  2.     public static void main(String[] args) throws DocumentException {
  3.         //1.获取解析器
  4.         SAXReader saxReader = new SAXReader();
  5.         //2.用解析器解析XML文件获得对于的Document对象
  6.         File file = new File("src/main/resources/a.xml");
  7.         Document document = saxReader.read(file);
  8.         //3.通过Xpath的API获取name元素
  9.         //(1)绝对路径
  10.         List<Element> list1 = document.selectNodes("/persons/person/name");
  11.         System.out.println("绝对路径获取name内容:一共"+list1.size()+"个");
  12.         for (Element element : list1) {
  13.             System.out.println(element.getText());
  14.         }
  15.         //(2)相对路径
  16.         Element rootElement = document.getRootElement();
  17.         List<Element> list2 = rootElement.selectNodes("./person/name");
  18.         System.out.println("相对路径获取name内容:一共"+list2.size()+"个");
  19.         for (Element element : list2) {
  20.             System.out.println(element.getText());
  21.         }
  22.         //(3)全文搜索
  23.         List<Element> list3 = document.selectNodes("//name");
  24.         System.out.println("全文搜索获取name内容:一共"+list3.size()+"个");
  25.         for (Element element : list3) {
  26.             System.out.println(element.getText());
  27.         }
  28.         //(4)属性搜索
  29.         Element node = (Element) document.selectSingleNode("//person[@id='1']/name");
  30.         System.out.println("属性搜索获取name内容:"+node.getText());
  31.     }
  32. }
复制代码
四、单位测试

1.什么是单位测试?为什么用它?

   单位测试就是,针对最小的功能单位编写测试代码,Java步伐最小的功能单位是方法,因此,单位测试就是针对Java方法的测试,进而检查方法的精确性。
  
  以前测试方法只有一个main方法,如果一个方法的测试失败了,其他方法测试会受到影响。还需要步伐员本身去观察测试是否成功。
  2.Junit单位测试框架

(1)简述

   JUnit是使用Java语言实现的单位测试框架,它是开源的,Java开发者都应当学习并使用JUnit编写单位测试。
  此外,险些所有的IDE工具都集成了JUnit,这样我们就可以直接在IDE中编写并运行JUnit测试,JUnit目前最新版本是5。
  (2)优点

   1.JUnit可以灵活的选择实行哪些测试方法,可以一键实行全部测试方法。
  2.单位测试中的某个方法测试失败了,不会影响其他测试方法的测试。
  3.运行成功是绿色,运行失败是红色
  (3)步骤

   

  (4)快速入门

   测试代码

  1. public class JunitDemo1 {
  2.     @Test
  3.     //输入注解@Test
  4.     //如果爆红就按alt+回车
  5.     //选择Junit4导入
  6.     public void method1() {
  7.         System.out.println(2/0);
  8.         int a = 100;
  9.         int b = 100;
  10.         System.out.println(a+b);
  11.     }
  12.     @Test
  13.     public void method2() {
  14.         int a = 100;
  15.         int b = 100;
  16.         System.out.println(a+b);
  17.     }
  18.     @Test
  19.     public void method3() {
  20.         int a = 100;
  21.         int b = 100;
  22.         System.out.println(a+b);
  23.     }
  24. }
复制代码
   测试结果

  

   (5)Junit常用注解


一般实际开发常用的就前面的3个注解,@Before,@Test,@After这三个注释配套使用
实际开发的测试原则就是,包管测试前后的数据,原原本本不变
   于是完整的单位测试步骤
  1.先实行的@Before的方法,对数据进行一个初始化的动作和数据的备份
  2.再实行@Test的方法,去真正的去测试方法,要共同断言,与期望数据做对比
  3.最后实行@After的方法,去还原数据
     Junit中一般的断言使用方法
  参数1:如果断言为假,就将message的信息输出到控制台
                          为真,就不输出
  参数2:期望得到的结果
  参数3:运行完测试方法得到的实际结果
  Assert.assertEquals(message,expected, actual);
  (6)完整的单位测试

   以后在实际开发中,如果想要测试一个方法是否精确,并不是直接在当火线法的上面写@Test的
  而是,本身独立编写一个测试类。(不要写main方法)
  在这个类中,编写一些方法。
  在方法内里调用要被测试的方法即可
    需求:
          测试File类中的delete方法是否誊写精确???
    代码
  独立写一个测试类,创建要测试的方法所在类的对象File,运行FIle对象的delete方法,
  测试方法必须数据备份和规复
  1. public class JunitDemo2 {
  2.     @Before
  3.     public void method1() throws IOException {
  4.         //数据备份
  5.         FileInputStream fis = new FileInputStream("logs\\a.txt");
  6.         FileOutputStream fos = new FileOutputStream("logs\\copy.txt");
  7.         int b;
  8.         while ((b=fis.read())!=-1){
  9.             fos.write(b);
  10.         }
  11.         fos.close();
  12.         fis.close();
  13.     }
  14.     @Test
  15.     public void method2(){
  16.         //测试File类的delete方法
  17.         File file = new File("logs\\a.txt");
  18.         //判断是否删除成功
  19.         boolean delete = file.delete();
  20.         //检查a.txt是否存在
  21.         boolean exists = file.exists();
  22.         Assert.assertEquals("delete方法出错了",true,delete);
  23.         Assert.assertEquals("delete方法出错了",false,exists);
  24.     }
  25.     @After
  26.     public void method3() throws IOException {
  27.         //数据恢复
  28.         FileInputStream fis = new FileInputStream("logs\\copy.txt");
  29.         FileOutputStream fos = new FileOutputStream("logs\\a.txt");
  30.         int b;
  31.         while ((b=fis.read())!=-1){
  32.             fos.write(b);
  33.         }
  34.         fos.close();
  35.         fis.close();
  36.         new File("logs\\copy.txt").delete();
  37.     }
  38. }
复制代码
 五、注解

1.简述

   Annotation体现注解。是JDK1.5的新特性。
  注解的重要作用:对我们的步伐进行标注。通过注解可以给类增长额外的信息。
  注解是给编译器或JVM看的,编译器或JVM可以根据注解来完成对应的功能。
  (注释是给人看的,编译阶段会注释擦除)
  2.常见的注解(掌握) 

   @Override:体现方法的重写
@Deprecated:体现修饰的方法已过期
@SuppressWarnings("all"): 压制告诫
  除此之外,还需要掌握第三方框架中提供的注解:
  好比:Junit
  @Test体现运行测试方法
  @Before体现在Test之前运行,进行数据的初始化
  @After体现在Test之后运行,进行数据的还原
   3.自界说注解

(1)界说格式

类似类的界说

(2)使用格式

   @注解名(属性名1=值1,属性名2=值2)
  注意:
          注解使用可以放在类,方法和属性的上面
          使用自界说注解时要包管注解每个属性都有值
          注解可以使用默认值 ,没有默认值的一定要赋值
     创建一个注解
  1. public @interface MyAnno1 {
  2.     String name();
  3.     int age() default 18;
  4. }
复制代码
使用 
  1. @MyAnno1(name = "张三")
  2. public class Test {
  3.     @MyAnno1(name = "王五",age = 20)
  4.     int age;
  5.     @MyAnno1(name = "李四")
  6.     public void method1(){
  7.         System.out.println("method1");
  8.     }
  9. }
复制代码
 (3)特别属性value

   value属性,如果只有一个value属性的情况下,使用value属性的时间可以省略value名称不写!!
  但是如果有多个属性,且多个属性没有默认值,那么vaue名称是不能省略的。
  常见的@SuppressWarnings("all"):就是只有一个value属性的注解
  4.元注解

   元注解就是注解的注解,就是写在注解上面的注解
  好比下面
   

  (1)两个元注解

    @Target:束缚自界说注解只能在哪些地方使用
   @Retention:申明注解的生命周期
    @Target

   @Target中可使用的值界说在ElementType罗列类(底层写好的)中,常用值如下
  TYPE,类,接口
  FIELD,成员变量
  METHOD,成员方法
  PARAMETER,方法参数
  CONSTRUCTOR,构造器
  LOCAL_VARIABLE,局部变量
  
     @Retention

  @Retention中可使用的值界说在RetentionPolicy罗列类中,常用值如下
  SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
  CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值
  RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)
  5.注解解析

(1)概念和作用

    注解的操作中经常需要进行解析,注解的解析就是判定是否存在注解,存在注解就解析出内容。
  举一个例子Junit框架中的@Test注解是怎么将测试方法运行起来的,这其中就是用到了注解解析。
   当运行测试方法的时间,@Test注解就会通过反射来获取对应方法的Method类,然后实行方法。
   (2)与注解解析相干的接口和方法

   Annotation:注解的顶级接口
  可以利用反射解析注解
  

  有的类身分Class,Method,Field,Constructor,都实现了AnnotatedElement接口他们都拥有解析注解的能力
  (3) 解析注解的技巧

   注解在哪个身分上,我们就先拿哪个身分对象。
  好比注解作用成员方法,则要得到该成员方法对应的Methed对象,再来拿上面的注解
  好比注解作用在类上,则要该类的class对象,再来拿上面的注解
  好比注解作用在成员变量上,则要得到该成员变量对应的Field对象,再来拿上面的注解
  
  共同后面的 模拟Junit框架明白
   6.模拟Junit框架

   需求

          界说若干个方法,只要加了MyTest注解,就可以在启动时被触发实行
  
    分析

          界说一个自界说注解MvTest,只能注解方法,存活范围是不停都在。
          界说若干个方法,只要有@MyTest注解的方法就能在启动时被触发实行,没有这个注解的方法不能实行。
    代码 

  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface MyTest {
  4. }
  5. public class MyTestMethod {
  6.     @MyTest
  7.     public void method1(){
  8.         System.out.println("method1");
  9.     }
  10.     public void method2(){
  11.         System.out.println("method2");
  12.     }
  13.     @MyTest
  14.     public void method3(){
  15.         System.out.println("method3");
  16.     }
  17. }
  18. public class MyTestDemo {
  19.     public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
  20.         //1,获取class对象
  21.         Class clazz = Class.forName("com.itheima.test2.MyTestMethod");
  22.         //获取对象
  23.         Object o = clazz.newInstance();
  24.         //2.获取所有方法
  25.         Method[] methods = clazz.getDeclaredMethods();
  26.         for (Method method : methods) {
  27.             //method依次表示类里面的每一个方法
  28.             method.setAccessible(true);
  29.             //判断当前方法有没有MyTest注解
  30.             if(method.isAnnotationPresent(MyTest.class)){
  31.                 method.invoke(o);
  32.             }
  33.         }
  34.     }
  35. }
复制代码
   运行结果 

  method1
  method3
  六、罗列类 

1.概念,使用和优缺点

可以查察【Java】罗列类型_java 罗列类-CSDN博客
2.重要的应用开发场景

   状态管理
  使用罗列类体现对象的差别状态,例如订单状态(待支付、已支付、已发货、已完成等)。
  错误代码
  界说各种错误类型或错误代码,以进步代码的可读性和可维护性。
  配置选项
  使用罗列类来封装常见的配置选项,例如日志级别(DEBUG、INFO、WARN、ERROR)或环境(开发、测试、生产)。
  类型安全的选择
  替代字符串常量,提供类型安全的选项,避免因拼写错误导致的题目,例如选择用户角色(ADMIN、USER、GUEST)。
  策略模式
  在实现策略模式时,可以使用罗列类来封装策略的实现,从而使代码更清楚。
  分类系统
  在需要分类的场景中,例如商品类别(电子产品、服饰、食品等),罗列类可以提供一种清楚的布局。
  API 计划
  在 API 中使用罗列类可以清楚地体现可选参数,使接口更加易于明白和使用。
  事件类型
  用于界说差别的事件类型,例如用户操作事件(点击、提交、查察等)。
  数据库映射
  将数据库中的状态值映射到应用步伐中的罗列类,简化数据操作。
  网络协议
  界说网络协议中的操作类型或消息类型,以进步代码的可读性。
  罗列类通过提供一组固定的常量值,能够使代码更清楚,更易于维护和扩展。



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

盛世宏图

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表