java基础进阶——log日志、类加载器、XML、单元测试、注解、枚举类

前言

这篇内容主要掌握的就是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文件将下面的依赖坐标导入项目

        <dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></dependency>

 刷新maven自动导入下面三个jar包

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

logback.xml内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration><!--CONSOLE :表示当前的日志信息是可以输出到控制台的。--><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><!--输出流对象 默认 System.out 改为 System.err--><target>System.out</target><encoder><!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level]  %c [%thread] : %msg%n</pattern></encoder></appender><!-- File是输出的方向通向文件的 --><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern><charset>utf-8</charset></encoder><!--日志输出路径--><file>C:/code/itpzh-data.log</file><!--指定日志文件拆分和压缩规则--><rollingPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!--通过指定压缩文件名称,来确定分割文件方式--><fileNamePattern>C:/code/itpzh-data2-%d{yyyy-MMdd}.log%i.gz</fileNamePattern><!--文件拆分大小--><maxFileSize>1MB</maxFileSize></rollingPolicy></appender><!--level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF, 默认debug<root>可以包含零个或多个<appender-ref>元素,标识这个输出位置将会被本日志级别控制。--><root level="info"><appender-ref ref="CONSOLE"/><appender-ref ref="FILE" /></root>
</configuration>

(3)入门程序

A.步骤

1.获取日志的对象。

private final static Logger LOGGER = LoggerFactory.getLogger("类对象");

注意:这个对象要全局共享唯一(static final修饰)

           这个Logger一定要是org.slf4j.Logger这个第三方包下的

2.用日志对象的方法记录系统的日志信息。

 B.入门实例代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Scanner;public class LoggerDemo1 {//获取一个共享的唯一的log日志对象private final static Logger LOGGER = LoggerFactory.getLogger(LoggerDemo1.class);public static void main(String[] args) {//获取用户登录的日志Scanner sr = new Scanner(System.in);while (true) {System.out.println("请输入用户名");String username = sr.next();System.out.println("请输入密码");String password = sr.next();if ("张三".equals(username) && "12345".equals(password)) {LOGGER.info("用户{}登录成功,密码为{}", username, password);break;} else {LOGGER.info("用户{}登录失败", username);}}}
}

运行完,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)代码演示证明

public class ClassLoaderDemo1 {public static void main(String[] args) {//获取系统类加载器ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();//获取系统类加载器的父加载器 --- 平台类加载器ClassLoader classLoader1 = systemClassLoader.getParent();//获取平台类加载器的父加载器 --- 启动类加载器ClassLoader classLoader2 = classLoader1.getParent();System.out.println("系统类加载器" + systemClassLoader);System.out.println("平台类加载器" + classLoader1);System.out.println("启动类加载器" + classLoader2);}
}

 运行结果

4. 双亲委派模型

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

5.ClassLoader 中的两个方法

方法名说明
public static ClassLoader getSystemClassLoader()获取系统类加载器
public InputStream getResourceAsStream(String name)加载某一个资源文件

实例代码

public class ClassLoaderDemo2 {public static void main(String[] args) throws IOException {//获取系统类加载器ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();//利用加载器去加载一个指定的文件//参数:文件的路径(放在maven项目的resources目录下,默认去那里加载)//返回值:字节流。InputStream is = systemClassLoader.getResourceAsStream("prop.properties");Properties properties = new Properties();properties.load(is);System.out.println(properties);is.close();}
}

三、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.步骤

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

  2. 看xml文件中使用了哪些元素

    <!ELEMENT> 可以定义元素

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

    简单元素:没有子元素。复杂元素:有子元素的元素;

  4. 简单元素修饰词

    ​ EMPTY: 表示标签体为空

    ​ ANY: 表示标签体可以为空也可以不为空

    ​ PCDATA: 表示该元素的内容部分为字符串

  5. 复杂元素修饰词​                                                                                                                   直接写子元素名称. 多个子元素可以使用","或者"|"隔开;​ ","表示定义子元素的顺序 ; "|": 表示子元素只能出现任意一个​ "?"零次或一次, "+"一次或多次, "*"零次或多次;如果不写则表示出现一次

  6. 元素的属性的定义

    格式

    定义一个属性的格式为:<!ATTLIST 元素名称 属性名称 属性的类型 属性的约束>属性的类型:​ CDATA类型:普通的字符串

    属性的约束:

    ​ // #REQUIRED: 必须的​ // #IMPLIED: 属性不是必需的​ // #FIXED value:属性值是固定的

B.代码

简单入门

<!ELEMENT persons (person)>
<!ELEMENT person (name,age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>

 复杂

<!ELEMENT persons (person+)>
<!ELEMENT person (name,age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ATTLIST person id CDATA #REQUIRED>

DTD约束引入

三种引入方式

简单入门代码
// 这是persondtd.dtd文件中的内容,已经提前写好
<!ELEMENT persons (person)>
<!ELEMENT person (name,age)>
<!ELEMENT name (#PCDATA)>
<!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>
复杂代码 
//dtd代码
<!ELEMENT persons (person+)>
<!ELEMENT person (name,age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!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的区别
  1. schema约束文件也是一个xml文件,符合xml的语法,这个文件的后缀名.xsd

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

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

  4. 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,判断当前元素是简单元素还是复杂元素

代码

<?xml version="1.0" encoding="UTF-8" ?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"targetNamespace="http://www.example.org/b"elementFormDefault="qualified"><element name="persons"><complexType><sequence maxOccurs="unbounded"><element name="person"><complexType><sequence><element name="name" type="string"/><element name="age" type="int"/></sequence></complexType></element></sequence></complexType></element>
</schema>
schema约束引入

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

选择后idea直接导入约束

 入门代码
//xsd代码
<?xml version="1.0" encoding="UTF-8" ?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"targetNamespace="http://www.example.org/b"elementFormDefault="qualified"><element name="persons"><complexType><sequence maxOccurs="unbounded"><element name="person"><complexType><sequence><element name="name" type="string"/><element name="age" type="int"/></sequence></complexType></element></sequence></complexType></element>
</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)快速入门

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

 (2)成员方法

 Element类

(3)最终示例

需求:

        将下面的XML文件的几个人的信息保存到内存中

建议:创建一个Person类来存储人物信息

<?xml version="1.0" encoding="UTF-8" ?>
<persons><person id="1"><name>张三</name><age>18</age></person><person id="2"><name>李四</name><age>20</age></person><person id="3"><name>张三</name><age>21</age></person>
</persons>

创建一个Person类

public class Person {private int id;private String name;private int age;public Person(int id, String name, int age) {this.id = id;this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}';}
}

正文代码

public class Dom4jDemo2 {public static void main(String[] args) throws DocumentException {//1.创建解析器对象SAXReader saxReader = new SAXReader();//2.利用解析器去读取XML文件,并返回文件对象File file = new File("src\\main\\resources\\a.xml");Document document = saxReader.read(file);//拿到了document表示我已经拿到了xml文件的整体//创建一个集合来存储人物的信息ArrayList<Person> list = new ArrayList<>();//下面一层一层的扒开获取里面的内容即可//获取根元素Element rootElement = document.getRootElement();//获取根元素下的所有person元素List<Element> elements = rootElement.elements("person");for (Element element : elements) {//获取子元素的id属性Attribute id = element.attribute("id");String idValue = id.getValue();//获取子元素的name和ageString nameValue = element.element("name").getText();String ageValue = element.element("age").getText();Person person = new Person(Integer.parseInt(idValue), nameValue, Integer.parseInt(ageValue));list.add(person);}list.stream().forEach(System.out::println);}
}

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文件内容如下

<?xml version="1.0" encoding="UTF-8" ?>
<persons><person id="1"><name>张三</name><age>18</age></person><person id="2"><name>李四</name><age>20</age></person><person id="3"><name>王五</name><age>21</age></person><name>基尼太妹</name>
</persons>

代码

public class XpathDemo {public static void main(String[] args) throws DocumentException {//1.获取解析器SAXReader saxReader = new SAXReader();//2.用解析器解析XML文件获得对于的Document对象File file = new File("src/main/resources/a.xml");Document document = saxReader.read(file);//3.通过Xpath的API获取name元素//(1)绝对路径List<Element> list1 = document.selectNodes("/persons/person/name");System.out.println("绝对路径获取name内容:一共"+list1.size()+"个");for (Element element : list1) {System.out.println(element.getText());}//(2)相对路径Element rootElement = document.getRootElement();List<Element> list2 = rootElement.selectNodes("./person/name");System.out.println("相对路径获取name内容:一共"+list2.size()+"个");for (Element element : list2) {System.out.println(element.getText());}//(3)全文搜索List<Element> list3 = document.selectNodes("//name");System.out.println("全文搜索获取name内容:一共"+list3.size()+"个");for (Element element : list3) {System.out.println(element.getText());}//(4)属性搜索Element node = (Element) document.selectSingleNode("//person[@id='1']/name");System.out.println("属性搜索获取name内容:"+node.getText());}
}

四、单元测试

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

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

以前测试方法只有一个main方法,如果一个方法的测试失败了,其他方法测试会受到影响。还需要程序员自己去观察测试是否成功。

2.Junit单元测试框架

(1)简述

JUnit是使用Java语言实现的单元测试框架,它是开源的,Java开发者都应当学习并使用JUnit编写单元测试。

此外,几乎所有的IDE工具都集成了JUnit,这样我们就可以直接在IDE中编写并运行JUnit测试,JUnit目前最新版本是5。

(2)优点

1.JUnit可以灵活的选择执行哪些测试方法,可以一键执行全部测试方法。

2.单元测试中的某个方法测试失败了,不会影响其他测试方法的测试。

3.运行成功是绿色,运行失败是红色

(3)步骤

(4)快速入门

测试代码
public class JunitDemo1 {@Test//输入注解@Test//如果爆红就按alt+回车//选择Junit4导入public void method1() {System.out.println(2/0);int a = 100;int b = 100;System.out.println(a+b);}@Testpublic void method2() {int a = 100;int b = 100;System.out.println(a+b);}@Testpublic void method3() {int a = 100;int b = 100;System.out.println(a+b);}
}
测试结果

 (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方法,

测试方法必须数据备份和恢复

public class JunitDemo2 {@Beforepublic void method1() throws IOException {//数据备份FileInputStream fis = new FileInputStream("logs\\a.txt");FileOutputStream fos = new FileOutputStream("logs\\copy.txt");int b;while ((b=fis.read())!=-1){fos.write(b);}fos.close();fis.close();}@Testpublic void method2(){//测试File类的delete方法File file = new File("logs\\a.txt");//判断是否删除成功boolean delete = file.delete();//检查a.txt是否存在boolean exists = file.exists();Assert.assertEquals("delete方法出错了",true,delete);Assert.assertEquals("delete方法出错了",false,exists);}@Afterpublic void method3() throws IOException {//数据恢复FileInputStream fis = new FileInputStream("logs\\copy.txt");FileOutputStream fos = new FileOutputStream("logs\\a.txt");int b;while ((b=fis.read())!=-1){fos.write(b);}fos.close();fis.close();new File("logs\\copy.txt").delete();}
}

 五、注解

1.简述

Annotation表示注解。是JDK1.5的新特性。

注解的主要作用:对我们的程序进行标注。通过注解可以给类增加额外的信息。

注解是给编译器或JVM看的,编译器或JVM可以根据注解来完成对应的功能。

(注释是给人看的,编译阶段会注释擦除)

2.常见的注解(掌握) 

@Override:表示方法的重写
@Deprecated:表示修饰的方法已过时
@SuppressWarnings("all"): 压制警告

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

比如:Junit

@Test表示运行测试方法

@Before表示在Test之前运行,进行数据的初始化

@After表示在Test之后运行,进行数据的还原

 3.自定义注解

(1)定义格式

类似类的定义

(2)使用格式

@注解名(属性名1=值1,属性名2=值2)

注意:

        注解使用可以放在类,方法和属性的上面

        使用自定义注解时要保证注解每个属性都有值

        注解可以使用默认值 ,没有默认值的一定要赋值

 创建一个注解

public @interface MyAnno1 {String name();int age() default 18;
}

使用 

@MyAnno1(name = "张三")
public class Test {@MyAnno1(name = "王五",age = 20)int age;@MyAnno1(name = "李四")public void method1(){System.out.println("method1");}
}

 (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注解的方法就能在启动时被触发执行,没有这个注解的方法不能执行。

代码 
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
}public class MyTestMethod {@MyTestpublic void method1(){System.out.println("method1");}public void method2(){System.out.println("method2");}@MyTestpublic void method3(){System.out.println("method3");}
}public class MyTestDemo {public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {//1,获取class对象Class clazz = Class.forName("com.itheima.test2.MyTestMethod");//获取对象Object o = clazz.newInstance();//2.获取所有方法Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {//method依次表示类里面的每一个方法method.setAccessible(true);//判断当前方法有没有MyTest注解if(method.isAnnotationPresent(MyTest.class)){method.invoke(o);}}}
}
运行结果 

method1

method3

六、枚举类 

1.概念,使用和优缺点

可以查看【Java】枚举类型_java 枚举类-CSDN博客

2.主要的应用开发场景

状态管理

使用枚举类表示对象的不同状态,例如订单状态(待支付、已支付、已发货、已完成等)。

错误代码

定义各种错误类型或错误代码,以提高代码的可读性和可维护性。

配置选项

使用枚举类来封装常见的配置选项,例如日志级别(DEBUG、INFO、WARN、ERROR)或环境(开发、测试、生产)。

类型安全的选择

替代字符串常量,提供类型安全的选项,避免因拼写错误导致的问题,例如选择用户角色(ADMIN、USER、GUEST)。

策略模式

在实现策略模式时,可以使用枚举类来封装策略的实现,从而使代码更清晰。

分类系统

在需要分类的场景中,例如商品类别(电子产品、服饰、食品等),枚举类可以提供一种清晰的结构。

API 设计

在 API 中使用枚举类可以清晰地表示可选参数,使接口更加易于理解和使用。

事件类型

用于定义不同的事件类型,例如用户操作事件(点击、提交、查看等)。

数据库映射

将数据库中的状态值映射到应用程序中的枚举类,简化数据操作。

网络协议

定义网络协议中的操作类型或消息类型,以提高代码的可读性。

枚举类通过提供一组固定的常量值,能够使代码更清晰,更易于维护和扩展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/402036.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二叉树(二)

一、二叉树的顺序结构 普通的二叉树是不适合用数组来存储的&#xff0c;因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆&#xff08;一种二叉树&#xff09;使用顺序结构的数组来存储&#xff0c;需要注意的是这里的堆和操作系统虚拟…

Self-Supervised Learning(李宏毅老师系列)

自学参考&#xff1a; BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding BERT 论文逐段精读 视频课 课件资料 笔记 一、概述 自监督学习模型与芝麻街~ 参数量 ELMO&#xff1a;94MBERT&#xff1a;340MGPT-2&#xff1a;1542MMegatron&…

ubuntu查看CPU、内存、硬盘

1、查看CPU cat /proc/cpuinfo 我这台机器CPU是2核&#xff0c;所以这里是2核 或者使用如下命令也可以查看 lscpu 查看CPU使用率 top 2、查看内存 查看内存信息&#xff1a; free -h 查看内存使用情况&#xff1a; vmstat 3、硬盘 查看硬盘使用情况&#xff1a; df -…

uniapp 日常业务 随便写写 源码

现成的组件 直接用 <template><view style"margin: 10rpx;"><view class"tea-header"><text class"tea-title">礼尚往来</text><view class"tea-view-all"><text>查看全部</text>&l…

免费录屏软件之QQ

录屏太简单了 1、首先下载QQ 2、在随便打开个对话框&#xff0c;再操作1、2步骤即可 3、嫌打开对话框麻烦&#xff1f; 4、打开QQ后直接按下CtrlAltR即可录屏&#xff0c;连对话框都不用打开了&#xff0c;按完快捷键后效果如下&#xff1a; 5、点击右下角开始录屏即可

Electron:摄像头录制和屏幕录制

摄像头录制 main.js const { app, BrowserWindow} require(electron)let mainWin null const createWindow () > {mainWin new BrowserWindow({width: 800,height: 600,title: 自定义菜单,webPreferences: {// 允许渲染进程使用nodejsnodeIntegration: true,// 允许渲…

idea付费插件激活

以下idea付费插件均可激活 获取链接&#xff1a;https://web.52shizhan.cn

【Qt开发】QtCharts图表 在ui上添加QChartView控件并进行绘图配置

【Qt开发】QtCharts图表 在ui上添加QChartView控件并进行绘图配置 文章目录 控件安装和模块导入在ui上添加QChartView控件QChartView图表配置附录&#xff1a;C语言到C的入门知识点&#xff08;主要适用于C语言精通到Qt的C开发入门&#xff09;C语言与C的不同C中写C语言代码C语…

Datawhale X 魔搭 AI夏令营 Task1 从零入门AI生图原理实践笔记

赛题内容 参赛者需在可图Kolors模型的基础上训练LoRA模型&#xff0c;生成无限风格&#xff0c;如水墨画风格、水彩风格、赛博朋克风格、日漫风格… 基于LoRA模型生成8张图片组成连贯故事&#xff0c;故事内容可自定义&#xff1b;基于8图故事&#xff0c;评估LoRA风格的美感度…

基于 Android studio 实现停车场管理系统--原创

目录 一、项目演示 二、开发环境 三、项目页面 四、项目详情 五、项目完整源码 一、项目演示 二、开发环境 三、项目详情 1.启动页 这段代码是一个简单的Android应用程序启动活动&#xff08;Activity&#xff09;&#xff0c;具体功能如下&#xff1a; 1. **延迟进入登…

【OpenCV】window 下 VS Code 配置OpenCV

文章目录 前言直接使用OpenCV 编译好的库自己编译OpenCVVS Code 安装MinGW下载下载Cmake编译OpenCV VS Code 运行cv程序VSCode配置运行CV程序 参考文章 前言 在网上找了些资料&#xff0c;大致得出VS Code开发OpenCV的环境配置流程&#xff0c;如下 安装VS Code安装MinGW安装…

【三维重建】Pixel-GS:三维高斯泼溅的像素感知的梯度密度控制(去除浮点,提升精度)

项目&#xff1a;https://pixelgs.github.io/ 标题&#xff1a;Pixel-GS: Density Control with Pixel-aware Gradient for 3D Gaussian Splatting 来源&#xff1a;香港大学&#xff1b;腾讯AI Lab 文章目录 摘要一、前言二、相关工作1.新视图合成2.基于点的辐射场3.Floater 的…

论文写作新神器!10款可以写论文的人工智能软件

在当今快速发展的数字时代&#xff0c;人工智能&#xff08;AI&#xff09;技术已经渗透到各个领域&#xff0c;包括学术研究和论文写作。为了帮助学者和学生提高写作效率和质量&#xff0c;市场上涌现了许多优秀的AI写作工具。本文将详细介绍10款可以写论文的人工智能软件&…

图像文本擦除无痕迹!复旦提出EAFormer:最新场景文本分割新SOTA!(ECCV`24)

文章链接&#xff1a;https://arxiv.org/pdf/2407.17020 git链接&#xff1a;https://hyangyu.github.io/EAFormer/ 亮点直击 为了在文本边缘区域实现更好的分割性能&#xff0c;本文提出了边缘感知Transformer&#xff08;EAFormer&#xff09;&#xff0c;该方法明确预测文…

CPU飙升 怎么定位问题

传统的方法 【top】 查看所有进程占系统CPU的排序&#xff0c;定位是哪个进程搞的鬼。PID那一列就是进程号。 【top -Hp pid】 定位进程中使用 CPU 最高的线程tid 【printf ‘0x%x’ tid】 线程 tid 转化 16 进制,例如printf ‘0x%x’ 11882 得到16进制的 0x2e6a 【jstack…

PX4-Autopolite linux环境下源码编译中遇到的一些问题及相应解决办法

最近在做一个PX4飞控移植的项目&#xff0c;第一次接触到PX4源码&#xff0c;真的是感觉编译起来非常的麻烦&#xff0c;下面我将介绍几个新手比较容易踩坑的点。 &#xff08;我都踩了ㄒ-ㄒ&#xff09; 1.PX4源码要用git clone 从github上克隆来&#xff0c;千万不要直接在g…

java SE--集合

1.Collection接口 Collection接口是List&#xff0c;Set&#xff0c;Queue接口的父接口&#xff0c;里面提供了子类的常用方法&#xff1b; List储存的是可以重复的&#xff0c;有序的数据&#xff0c;子类是arrayList&#xff08;数组结构&#xff09;和linkedList&#xff…

Mapreduce_Distinct数据去重

MapReduce中数据去重 输入如下的数据&#xff0c;统计其中的地址信息&#xff0c;并对输出的地址信息进行去重 实现方法&#xff1a;Map阶段输出的信息K2为想要去重的内容&#xff0c;利用Reduce阶段的聚合特点&#xff0c;对K2进行聚合&#xff0c;去重。在两阶段中&#xff…

24/8/15算法笔记 强化学习贪婪算法,UCB,汤普森算法

以老虎机为例介绍各算法 import numpy as np#每个老虎机的中奖概率&#xff0c;0-1之间均匀分布 probs np.random.uniform(size10)#生成一个数组&#xff0c;其中的元素是从均匀分布&#xff08;也称为矩形分布&#xff09;中随机抽取的。均匀分布意味着每个数出现的概率是相…

微服务架构的未来发展趋势

文章目录 摘要引言当前发展趋势ServerlessService MeshAIOps 未来可能出现的挑战代码示例微服务架构示例 QA环节小结未来展望参考资料 摘要 微服务架构在软件开发中已经成为主流&#xff0c;但随着市场需求和技术环境的快速变化&#xff0c;微服务架构也在不断演进。本文将分析…