写在前面:
每一个不曾起舞的日子,都是对生命的辜负。
希望看到这里的每一个人都能努力学习,不负韶华,成就更好的自己。
以下仅是个人学习过程中的一些想法与感悟,Java知识博大精深,作为初学者,个人能力有限,哪里写的不够清楚、明白,还请各位不吝指正,欢迎交流与讨论。如果有朋友因此了解了一些知识或对Java有了更深层次的理解,从而进行更进一步的学习,那么这篇文章的意义也就达到了。
目录
XML、XML解析、设计模式
1.XML
1.1XML概述
XML概述
XML是可扩展标记语言(eXtensible Markup Language)的缩写,它是是一种数据表示格式,可以用于自定义数据格式,描述非常复杂的数据结构,常用于传输和存储数据。
XML示例如下图所示。
XML的几个特点和使用场景
①纯文本,默认使用UTF-8编码,可嵌套;
②如果把XML内容存为文件,那么它就是一个XML文件;
③XML的使用场景:XML内容经常被当成消息进行网络传输,或者作为配置文件用于存储系统的配置信息。
1.2XML的创建、语法规则
XML的创建
就是创建一个XML类型的文件,要求文件的后缀必须使用xml,如hello_world.xml
XML的语法规则
XML文件的后缀名为:xml
文档声明必须是第一行
如<?xmversion="1.0" encoding="UTF-8" ?>
version:XML默认的版本号码、该属性是必须存在的。
encoding:本XML文件的编码。
XML的标签(元素)规则
标签由一对尖括号和合法标识符组成:<name></name>,必须存在一个根标签,有且只能有一个。
标签必须成对出现,有开始,有结束:<name></name>
特殊的标签可以不成对,但是必须有结束标记,如:<br/>
标签中可以定义属性,属性和标签名空格隔开,属性值必须用双引号引起来<student id = “1”></name>
标签需要正确的嵌套。
XML的其他组成
XML文件中可以定义注释信息:<!– 注释内容 -->
XML文件中某些需要替代的特殊字符
字符 |
替代值 |
含义 |
< |
< |
小于 |
> |
> |
大于 |
& |
& |
和 |
' |
' |
单引号 |
" |
" |
双引号 |
XML文件中可以存在CDATA区:<![CDATA[ …内容… ]]>,里面的内容可以随意填写,无需使用字符替代某些特殊字符,IDEA中的快捷键”CD”。
1.3XML文档约束方式
什么是文档约束?
由于XML文件可以自定义标签,导致XML文件可以随意定义,程序在解析的时候可能出现问题。文档约束是用来限定xml文件中的标签以及属性应该怎么写,以此强制约束程序员必须按照文档约束的规定来编写xml文件。
文档约束的分类:DTD、schema
使用文档约束的步骤
①:编写schema约束文档,后缀必须是.xsd(编写DTD约束文档,后缀必须是.dtd),具体的形式到代码中观看。
②:在需要编写的XML文件中导入该schema(DTD)约束文档
③:按照约束内容编写XML文件的标签。
注:文档约束-DTD可以约束XML文件的编写,不能约束具体的数据类型。schema本身也是一个xml文件,本身也受到其他约束文件的要求,所以编写的更加严谨,可以约束具体的数据类型,约束能力上更强大。
2.XML解析技术
2.1XML解析技术概述
XML的数据的作用是什么,最终需要怎么处理?
存储数据、做配置信息、进行数据传输,最终需要被程序进行读取,解析里面的信息。
什么是XML解析
使用程序读取XML中的数据。
两种解析方式:SAX解析、DOM解析
DOM解析解析文档对象模型图示如下图所示。
其中,整个xml文档称为Document对象;Element对象代表标签(图示蓝色区域);Attribute对象代表属性(图示紫色区域);Text对象代表文本内容(图示黄色区域),且后三者均实现了Node接口。
Dom解析常用框架:Dom4j:把文件一次性加载到内存中,加载为Document对象再操作。
2.2Dom4J解析XML文件
Dom4J的解析思想?
得到文档对象Document,从中获取元素对象和内容。
导入Dom4J框架步骤
① 下载Dom4j框架,官网下载。 ② 在项目中创建一个文件夹:lib ③ 将dom4j-2.1.1.jar文件复制到 lib 文件夹。④ 在jar文件上点右键,选择 Add as Library -> 点击OK ⑤ 在类中导包使用。
Dom4j解析XML-得到Document对象
SAXReader类构造器
方法名 |
说明 |
public SAXReader() |
创建Dom4J的解析器对象 |
SAXReader类得到Document的方法
方法名 |
说明 |
Document read(String url) |
加载XML文件成为Document对象 |
Dom4j解析XML的元素、属性、文本
Document类得到根元素的方法
方法名 |
说明 |
Element getRootElement() |
获得根元素对象 |
各级元素的方法
方法名 |
说明 |
List<Element> elements() |
得到当前元素下所有下一级子元素 |
List<Element> elements(String name) |
得到当前元素下指定名字的子元素返回集合 |
Element element(String name) |
得到当前元素下指定名字的子元素, 如果有很多名字相同的返回第一个 |
String getName() |
得到元素名字 |
String attributeValue(String name) |
通过属性名(如果有)直接得到属性值 |
String elementText(子元素名) |
得到指定名称的子元素 (此子元素只有文本,不含有子元素)的文本 |
String getText() |
得到(此元素只有文本,不含有子元素)文本 |
示例代码如下:
public class Dom4JHelloWorld {
@Test
public void parseXMLData() throws Exception {
// 1.创建一个Dom4j的解析器对象,代表整个dom4j框架
SAXReader saxReader = new SAXReader();
// 2.把XML文件加载到内存中称为一个Document文档对象
// Document document = saxReader.read(new File("day15_xml_app\\src\\Contacts.xml"));
// 此种通过File对象寻找的方式的缺点:需要通过模块名寻找,一旦模块名被修改,会找不到
// getResourceAsStream中的"/"是直接去src下寻找文件
InputStream is = Dom4JHelloWorld.class.getResourceAsStream("/Contacts.xml");
// 通过此种方式找到文件字节输入流,再传递给read方法,即使模块名修改,不影响找到该xml文件
Document document = saxReader.read(is);
// 获取根元素
Element root = document.getRootElement();
System.out.println(root.getName()); // contactList
}
}
注:getResourceAsStream中的"/"是直接去src下寻找文件,不受模块改名的影响。如InputStream is = Dom4JHelloWorld.class.getResourceAsStream("/Contacts.xml");
XML解析案例
需求:利用Dom4J的知识,将Contact.xml文件中的联系人数据封装成List集合,其中每个元素是实体类Contact。打印输出 List 中的每个元素。
示例代码如下:
Contact.xml
<?xmversion="1.0" encoding="UTF-8"?>
<contactList>
<contact id="1" vip="true">
<name> 潘金莲 </name>
<gender>女</gender>
<email>panpan@itcast.cn</email>
</contact>
<contact id="2" vip="false">
<name>武松</name>
<gender>男</gender>
<email>wusong@itcast.cn</email>
</contact>
<contact id="3" vip="false">
<name>武大狼</name>
<gender>男</gender>
<email>wuda@itcast.cn</email>
</contact>
<user>
</user>
</contactList>
Contact类
public class Contact {
private int id;
private boolean vip;
private String name;
private char sex;
private String email;
public Contact() {
}
public Contact(int id, boolean vip, String name, char sex, String email) {
this.id = id;
this.vip = vip;
this.name = name;
this.sex = sex;
this.emai= email;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public boolean isVip() {
return vip;
}
public void setVip(boolean vip) {
this.vip = vip;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.emai= email;
}
@Override
public String toString() {
return "Contact{" +
"id=" + id +
", vip=" + vip +
", name='" + name + '\'' +
", sex=" + sex +
", email='" + emai+ '\'' +
'}';
}
}
测试类
public class Dom4JTest2 {
@Test
public void parseToList() throws Exception {
// 1.导入Dom4J框架
// 2.创建SAXReader对象
SAXReader saxReader = new SAXReader();
// 3.加载XML文件称为Document对象
Document document = saxReader.read(Dom4JTest2.class.getResourceAsStream("/Contacts.xml"));
// 4.获取根元素
Element root = document.getRootElement();
// 5.提取contact子元素
List<Element> contactEles = root.elements("contact");
// 6.准备ArrayList集合封装联系人信息
List<Contact> contactList = new ArrayList<>();
// 7.遍历contact子元素
for (Element contactEle : contactEles) {
// xml文件中的值都是文本,需要使用包装类进行类型转换
// 此处不能用强转,需要使用类型转换,强转必须保证被强转的变量类型就是强转后的类型才可以
int contactId = Integer.valueOf(contactEle.attributeValue("id"));
boolean contactIsVip = Boolean.valueOf(contactEle.attributeValue("vip"));
String contactName = contactEle.elementTextTrim("name");
char contactSex = contactEle.elementTextTrim("gender").charAt(0);
String contactEmai= contactEle.elementTextTrim("email");
// 8.每一个子元素都是一个联系人对象
// 9.把联系人对象加入到contactList集合中
contactList.add(new Contact(contactId, contactIsVip,
contactName, contactSex, contactEmail));
}
// 10.遍历contactList集合
for (Contact contact : contactList) {
System.out.println(contact);
}
}
}
程序运行结果如下:
Contact{id=1, vip=true, name='潘金莲', sex=女, email='panpan@itcast.cn'}
Contact{id=2, vip=false, name='武松', sex=男, email='wusong@itcast.cn'}
Contact{id=3, vip=false, name='武大狼', sex=男, email='wuda@itcast.cn'}
注:xml文件中的值都是文本,需要进行类型转换,不能用强转。强转必须保证被强转的变量类型就是强转后的类型(向下转型)才可以,类型转换是不同类型之间的变量的相互转换。
Dom4J的解析后的数据形式通常数据会封装成Java的对象,如单个对象,或者集合对象的形式。
一键修改所有出现该变量的变量名:Shift + F6。
3.XML检索技术:Xpath
如果需要从XML文件中检索需要的某个信息(如name)怎么解决?
Dom4j需要进行文件的全部解析,然后再寻找数据。
Xpath技术更加适合做信息检索。
XPath介绍
XPath在解析XML文档方面提供了一独树一帜的路径思想,更加优雅,高效。
XPath使用路径表达式来定位XML文档中的元素节点或属性节点。
使用Xpath检索出XML文件
需求:使用Dom4J把一个XML文件的数据进行解析。
分析:
① 导入jar包(dom4j和jaxen-1.1.2.jar),Xpath技术依赖Dom4j技术
② 通过dom4j的SAXReader获取Document对象
③ 利用XPath提供的API,结合XPath的语法完成选取XML文档元素节点进行解析操作。
Document中与Xpath相关的API
方法名 |
说明 |
Node selectSingleNode("表达式") |
获取符合表达式的唯一元素 |
List<Node> selectNodes("表达式") |
获取符合表达式的元素集合 |
Xpath的四大检索方案:绝对路径、相对路径、全文检索、属性查找
XPath:绝对路径:采用绝对路径获取从根节点开始逐层的查找/contactList/contact/name节点列表并打印信息:/根元素/子元素/孙元素,从根元素开始,一级一级向下查找,不能跨级。
XPath:相对路径:采用相对路径获取当前元素下一级contact 节点的name子节点并打印信息:./子元素/孙元素,从当前元素开始,一级一级向下查找,不能跨级。
XPath:全文搜索:直接全文搜索所有的name元素并打印。
//contact:找contact元素,无论元素在哪里。
//contact/name:找name,无论在哪一级,但name一定是contact的子节点。
//contact//name:contact无论在哪一种,name只要是contact的子孙元素都可以找到。
XPath:属性查找:在全文中搜索属性,或者带属性的元素。
//@属性名:查找属性对象,无论是哪个元素,只要有这个属性即可。
//元素[@属性名]:全文搜索查找含有此属性的元素对象。
//元素//[@属性名=‘值’]:全文搜索查找含有此属性且属性值值为’值’的元素对象。
4.设计模式:工厂模式
什么是工厂设计模式?
之前我们创建类对象时,都是使用new对象的形式创建,在很多业务场景下也提供了不直接new的方式。
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种获取对象的方式。
工厂设计模式的作用:
工厂的方法可以封装对象的创建细节,比如:为该对象进行加工和数据注入。
可以实现类与类之间的解耦操作,只需要在FactoryPattern中维护,其他使用到的地方一并修改(核心思想)。
示例代码如下:
电脑类
public abstract class Computer {
private String name;
private double price;
public Computer() {
}
abstract void start();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
苹果电脑类
public class Mac extends Computer{
@Override
void start() {
System.out.println(this.getName() + "苹果电脑启动了");
}
}
华为电脑类
public class Huawei extends Computer{
@Override
void start() {
System.out.println(this.getName() + "华为电脑启动了");
}
}
工厂类
public class FactoryPattern {
/*
定义一个方法,创建对象并返回
*/
public static Computer creatComputer(String info) {
switch (info) {
case "华为":
Computer c = new Huawei();
c.setName("Huawei pro 16");
c.setPrice(5999);
return c;
case "苹果":
Computer c2 = new Mac();
c2.setName("Mac pro 2");
c2.setPrice(11999);
return c2;
default:
return null;
}
}
}
工厂模式测试类
public class FactoryDemo {
public static void main(String[] args) {
Computer c1 = FactoryPattern.creatComputer("华为");
c1.start(); // Huawei pro 16华为电脑启动了
Computer c2 = FactoryPattern.creatComputer("苹果");
c2.start(); // Mac pro 2苹果电脑启动了
}
}
5.设计模式:装饰模式
什么是装饰设计模式?
创建一个新类,包装原始类,从而在新类中提升原来类的功能。
装饰设计模式的作用:
作用:装饰模式指的是在不改变原类的基础上,动态地扩展一个类的功能。
装饰模式示例如下图所示。
装饰模式具体步骤如下:
①定义父类。
② 定义原始类,继承父类,定义功能。
③ 定义装饰类,继承父类,包装原始类(在原始类的基础上进行方法改进),增强功能。
示例代码如下:
接口类(共同父类)
public abstract class InputStream {
public abstract int read();
public abstract int read(byte[] buffer);
}
原始类
public class FileInputStream extends InputStream {
@Override
public int read() {
System.out.println("以低性能的方式读取了一个字节a");
return 97;
}
@Override
public int read(byte[] buffer) {
buffer[0] = 97;
buffer[1] = 98;
buffer[2] = 99;
System.out.println("以低性能的方式读取了一个字节数组" + Arrays.toString(buffer));
return 3;
}
}
装饰类
public class BufferedInputStream extends InputStream {
private InputStream is;
public BufferedInputStream(InputStream is) {
this.is = is;
}
@Override
public int read() {
System.out.println("提供8kb的缓冲区,提高读取性能");
return this.is.read();
}
@Override
public int read(byte[] buffer) {
System.out.println("提供8kb的缓冲区,提高读取性能");
return this.is.read(buffer);
}
}
测试类
public class DecoratorPattern {
public static void main(String[] args) {
InputStream is = new BufferedInputStream(new FileInputStream());
System.out.println(is.read());
System.out.println(is.read(new byte[3]));
}
}
程序运行结果如下:
提供8kb的缓冲区,提高读取性能
以低性能的方式读取了一个字节a
97
提供8kb的缓冲区,提高读取性能
以低性能的方式读取了一个字节数组[97, 98, 99]
3
写在最后:
感谢读完!
纵然缓慢,驰而不息!加油!