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.步骤
创建一个文件,这个文件的后缀名为.dtd
看xml文件中使用了哪些元素
<!ELEMENT> 可以定义元素
判断元素是简单元素还是复杂元素
简单元素:没有子元素。复杂元素:有子元素的元素;
简单元素修饰词
EMPTY: 表示标签体为空
ANY: 表示标签体可以为空也可以不为空
PCDATA: 表示该元素的内容部分为字符串
复杂元素修饰词 直接写子元素名称. 多个子元素可以使用","或者"|"隔开; ","表示定义子元素的顺序 ; "|": 表示子元素只能出现任意一个 "?"零次或一次, "+"一次或多次, "*"零次或多次;如果不写则表示出现一次
元素的属性的定义
格式
定义一个属性的格式为:<!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的区别
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,判断当前元素是简单元素还是复杂元素
代码
<?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 中使用枚举类可以清晰地表示可选参数,使接口更加易于理解和使用。
事件类型:
用于定义不同的事件类型,例如用户操作事件(点击、提交、查看等)。
数据库映射:
将数据库中的状态值映射到应用程序中的枚举类,简化数据操作。
网络协议:
定义网络协议中的操作类型或消息类型,以提高代码的可读性。
枚举类通过提供一组固定的常量值,能够使代码更清晰,更易于维护和扩展。
相关文章:
java基础进阶——log日志、类加载器、XML、单元测试、注解、枚举类
前言 这篇内容主要掌握的就是logback使用、理解类加载器、XML文件的编写,XML文档约束schema,用Dom4j解析XML文档,Xpath检索XML文档,完整使用Junit单元测试框架常用部分,注解的定义和使用,枚举类的定义和开发…...
《向量数据库指南》——控制Chatbot对话内容:Dopple AI的创新实践与用户体验优化
控制Chatbot对话内容:Dopple AI的创新实践与用户体验优化 在Chatbot技术日益成熟的今天,如何有效地控制对话内容,以满足用户多样化的需求,成为了开发者们关注的焦点。Dopple AI,作为一款先进的聊天机器人平台,通过其独特的交互设计和后端技术支持,为用户提供了前所未有…...
构建实时数据仓库:流式处理与实时计算技术解析
目录 一、流式处理 请求与响应 批处理 二、实时计算 三、Lambda架构 Lambda架构的缺点 四、Kappa架构 五、实时数据仓库解决方案 近年来随着业务领域的不断拓展,尤其像互联网、无线终端APP等行业应用的激增,产生的数据量呈指数级增长,对海量数…...
python算术表达式遗传算法
import random import operator import math# 定义可能的运算符和操作 ops {: ,-: -,*: *,/: /,sin: math.sin,cos: math.cos }# 随机生成一个表达式(个体) def generate_expression(depth0):if depth > 2: # 限制表达式的最大深度return str(rando…...
net.sf.jsqlparser.statement.select.SelectItem
今天一启动项目,出现了这个错误,仔细想了想,应该是昨天合并代码,导致的mybatis-plus版本冲突,以及分页PageHelper版本不兼容 可以看见这个我是最下边的 Caused by 报错信息,这个地方提示我 net .s…...
lua匹配MAC地址 正则表达式
LUA的正则表达式匹配很弱智,能不用lua就不要用lua。 %x表示十六进制数值 (%x%x):(%x%x):(%x%x):(%x%x):(%x%x):(%x%x)它不允许这样用: ((%x%x):){5}(%x%x)mac这还算好办,ipv4就难了,ipv6不可能,这样写下来那一串表达…...
Chainlit快速实现AI对话应用并将聊天数据的AWS S3 和 Azure Blob云服务中
自定义数据层 Literal AI 提供了最简单的方法来保存、分析和监控您的数据。 如果您正在考虑实现自定义数据层,请查看此处的示例以获取一些启发。 此外,我们非常希望看到社区主导的开源数据层实现并将其列在这里。如果您有兴趣做出贡献,请通过 Discord 与我们联系。 您需…...
浅谈性能优化(基于C++)
本文主要针对C的性能优化方法展开讨论。虽然这些方法也适用于一些其他语言,但由于C经常用于底层操作,提供了更多的优化空间;相比之下,诸如Python、Kotlin等高级语言由于其抽象程度更高,优化空间较少。 性能优化原理 …...
Python 报错:ModuleNotFoundError: No module named ‘Crypto‘
Crypto报错解决方案 Python 报错:ModuleNotFoundError: No module named Crypto前言问题解决方案 Python 报错:ModuleNotFoundError: No module named ‘Crypto’ 前言 Crypto是一个加密模块,它包含了多种加密算法,如 AES、DES、…...
UE(User Equipment) 和 UA(User Agent)
UE(User Equipment) UE 是 用户设备,这是一个泛指的术语,涵盖了所有类型的终端设备,例如手机、电脑、平板、智能手表等。这些设备可以连接到网络并进行通信。UE可以包含多种功能,包括对话(语音…...
视觉SLAM ch3补充——在Linux中配置VScode以及CMakeLists如何添加Eigen库
ch3中的所有代码,除了在kdevelop中运行,还可以在VScode中运行。下面将简要演示配置过程,代码不再做解答,详细内容在下面的文章中。(这一节中的pangolin由于安装过程中会出现很多问题,且后续内容用不到该平台…...
开关电源:优化电子产品中的能源使用
电压转换器是许多技术系统的支柱。根据应用的不同,所需的电源单元由变压器、整流器 AC/DC 转换器实现。当高性能开关电源尚未上市时,几乎只使用 50 Hz 变压器解决方案。 电源注意事项 电能几乎完全以三相电流的形式提供,系统电压为 10 ...3…...
Java语言程序设计——篇十三(2)
🌿🌿🌿跟随博主脚步,从这里开始→博主主页🌿🌿🌿 欢迎大家:这里是我的学习笔记、总结知识的地方,喜欢的话请三连,有问题可以私信🌳🌳&…...
python结合csv和正则实现条件筛选数据统计分数
前景提要: 有一个项目的数值和员工统计的对不上,如果一页一页翻找自己手动算,一个就有16、7页, 功能实现 1、创建csv文件 需要将每一个模块的所有数据头提取出来,这个可以直接用爬虫或者手工复制出来,因…...
Ubuntu系统的基础操作和使用|Linux|安装|网络连接|更新与升级系统|系统维护|故障排除|监控|桌面环境|虚拟机|快捷键
目录 1. Ubuntu系统的安装与初步设置 1.1 下载与安装Ubuntu 1.2 创建用户和设置密码 1.3 配置网络连接 1.4 更新与升级系统 2. Ubuntu的基本操作 2.1 文件与目录管理 2.2 系统进程管理 2.3 软件安装与管理 2.4 权限与用户管理 3. 系统维护与故障排除 3.1 系统日志查…...
day 38
2824.统计和小于目标的下标对数目 int countPairs(int* nums, int numsSize, int target){int x0;for(int i0;i<numsSize;i){for(int ji1;j<numsSize;j){if(nums[i]nums[j]<target){x;}}}return x; }2951.找出峰值 int* findPeaks(int* mountain, int mountainSize,…...
352532
c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话: 知不足而奋进,望远山而前行&am…...
Day.38 | 1143.最长公共子序列 1035.不相交的线 53.最大子序和 392.判断子序列
1143.最长公共子序列 要点:dp[i][j] dp[i - 1][j - 1] 1; dp[i][j] max(dp[i - 1][j], dp[i][j - 1]); class Solution { public:int longestCommonSubsequence(string text1, string text2) {vector<vector<int>> dp(text1.size() 1, vector<…...
pytorch 3 计算图
计算图结构 分析: 起始节点 ab 5 - 3ac 2b 3d 5b 6e 7c d^2f 2e最终输出 g 3f - o(其中 o 是另一个输入) 前向传播 前向传播按照上述顺序计算每个节点的值。 反向传播过程 反向传播的目标是计算损失函数(这里假设为…...
一文吃透:暗水印是什么?企业防泄密可以加暗水印吗?
设计部主管:昨天下班的时候我在办公室捡到一张文件,上面可是我们最新产品的设计草稿,严禁打印的,到底是谁干的? 员工:办公室没有监控,似乎很难查到哦。 网络部经理:不用担心&#…...
Ajax-02.Axios
Axios入门 1.引入Axios的js文件 <script src"js/axios-0.18.0.js"></script> Axios 请求方式别名: axios.get(url[,config]) axios.delete(url[,config]) axios.post(url[,data[,config]]) axios.put(url[,data[,config]]) 发送GET/POST请求 axios.get…...
NodeJS的核心配置文件package.json和package.lock.json详解
package.json 文件 package.json 文件是 Node.js 项目的核心配置文件,它包含了项目的基本信息、依赖关系以及一些脚本命令等。以下是 package.json 文件的主要字段说明: name:项目的名称,必须是小写,可以包含字母、数…...
开源数据采集和跟踪系统:助力营销决策的关键工具
开源数据采集和跟踪系统:助力营销决策的关键工具 在现代营销中,数据是最重要的资产之一。了解用户行为、优化广告效果、提升转化率,这一切都离不开精准的数据分析。为了帮助商家更好地掌握这些数据,市场上出现了许多开源的数据采…...
Luminar Neo for Mac/Win:创新AI图像编辑软件的强大功能
Luminar Neo,这款由Skylum公司倾力打造的图像编辑软件,为Mac和Windows用户带来了前所未有的创作体验与编辑便利。作为一款融合了先进AI技术的图像处理工具,Luminar Neo以其独特的功能和高效的操作流程,成为了摄影师、设计师及摄影…...
Mac平台M1PRO芯片MiniCPM-V-2.6网页部署跑通
Mac平台M1PRO芯片MiniCPM-V-2.6网页部署跑通 契机 ⚙ 2.6的小钢炮可以输入视频了,我必须拉到本地跑跑。主要解决2.6版本默认绑定flash_atten问题,pip install flash_attn也无法安装,因为强制依赖cuda。主要解决的就是这个问题,还…...
MyBatis:Maven,Git,TortoiseGit,Gradle
1,Maven Maven是一个非常优秀的项目管理工具,采用一种“约定优于配置(CoC)”的策略来管理项目。使用Maven不仅可以把源代码构建成可发布的项目(包括编译、打包、测试和分发),还可以生成报告、生…...
获取链表中间位置的两种方法方法
方法一: 我们可以计算链表节点的数量,然后遍历链表找到前半部分的尾节点。 方法二: 我们也可以使用快慢指针在一次遍历中找到:慢指针一次走一步,快指针一次走两步,快慢指针同时出发。当快指针移动到链表的末尾时&am…...
第二十天的学习(2024.8.8)Vue拓展
昨天的笔记中,我们进行的项目已经可以在网页上显示查询到数据库中的数据,今天的笔记中将会完成在网页上进行增删改查的操作 1.删除表中数据 现在网页上只能呈现出数据库中的数据,我们首先添加一个删除按钮,使其可以对数据库数据…...
微信小程序教程011:全局配置:Window
文章目录 1、window1.1、`window`-小程序窗口的组成部分1.2、了解 window 节点常用的配置项1.3、设置导航栏的标题1.4、设置导航栏的背景色1.5、设置导航栏的标题颜色1.6、全局开启下拉刷新功能1.7、设置下拉刷新时窗口的背景色1.8、设置下拉刷新时 loading 的样式1.9、设置上拉…...
Tomcat服务器和Web项目的部署
目录 一、概述和作用 二、安装 1.进入官网 2.Download下面选择想要下载的版本 3.点击Which version查看版本所需要的JRE版本 4.返回上一页下载和电脑和操作系统匹配的Tomcat 5. 安装完成后,点击bin目录下的startup.bat(linux系统下就运行startup.sh&…...
wordpress关闭邮件验证/郑州seo排名优化公司
又是一年双十一,相信又会有一大批相关的数据分析报告铺天盖地的飞来。而且,似乎每个人都觉得自己的数据分析图表做的很炫酷,额……今天小编决定拿出一大波反面教材,狠狠吐槽一番!????♂️ 错 误 图 表 案 例 11…...
企业网站代码怎么优化/域名注册服务网站
【问题】之前虽然已经实现了,可以通过在新建的线程中,及时动态更新进度条的问题了:但是结果却在:Toast.makeText(getApplicationContext(), "歌曲下载完毕", Toast.LENGTH_SHORT).show();的位置,导致程序崩溃…...
做平面免费接单网站/品牌网络营销案例
map:数据的插入 在构造map容器后,我们就可以往里面插入数据了。这里讲三种插入数据的方法:第一种:用insert函数插入pair数据map<int, string> mapStudent;mapStudent.insert(pair<int, string>(1,“student_one”)); 第二种&…...
湛江网站建设招聘/温州seo教程
1 总结:当数组名传入到函数作为参数时,被退化为指向首元素的指针 2 vscode c 工程初始化 https://zhuanlan.zhihu.com/p/87864677 https://zhuanlan.zhihu.com/p/348110926 下载seh 环境变量设置 3 总结:当数组名传入到函数作为参数时&…...
大连手机自适应网站建设报价/企业网站推广策略
0 前情介绍 使用matplotlib的subplot时,由于默认间距不大,所以可能导致出的图会挤在一起 import matplotlib.pyplot as pltplt.subplot(221) plt.plot([1, 2, 3])plt.subplot(222) plt.bar([1, 2, 3], [4, 5, 6])plt.xlabel(xlabel, fontsize15, color…...
wordpress创建配置文件/活动推广方式都有哪些
258. Add Digits Digit root 数根问题 /*** param {number} num* return {number}*/ var addDigits function(num) {var b (num-1) % 9 1 ;return b; };//之所以num要-1再1;是因为特殊情况下:当num是9的倍数时,09的数字根和0的数字根不同。 性质说明 …...