XML解析
来源:互联网 发布:淘宝网商贷款逾期了 编辑:程序博客网 时间:2024/05/17 07:22
1. XML总结
1.1. XML简介
XML : 可扩展的标记语言。(和HTML非常类似的)
- 可扩展的。
- 自定义的标签。
与HTML区别: XML传输数据,HTML是显示数据。
XML的版本: XML1.0(几乎都使用该版本) XML1.1(不向下兼容)
做什么用?=>描述有关系的数据
应用
1. 作为配置文件。
2. 可以在系统与系统之间进行数据的传输。
* webserivice soap XML封装数据
* json 和XML概念相似
1.2. XML基本语法
文档声明(*)
- 写法:
1.3. XML约束
约束的分类
* DTD
* schema
hello.java
<猫/>
- 格式良好的XML:遵循语法规范。
- 有效的XML:有约束。
1.3.1. XML约束–DTD 约束
DTD的约束
- 快速入门
快速入门的步骤:
- 需要出现哪些标签?
- 在DTD的文件中编写元素
<?xml version="1.0" encoding="UTF-8"?> <!ELEMENT 班级 (学生+)> <!ELEMENT 学生 (姓名,年龄,身高,体重)> <!ELEMENT 姓名 (#PCDATA)> <!ELEMENT 年龄 (#PCDATA)> <!ELEMENT 身高 (#PCDATA)> <!ELEMENT 体重 (#PCDATA)> <!ATTLIST 班级 编号 ID #REQUIRED 年级 CDATA "三年级" 学校名 CDATA #FIXED "西北工业大学" > <!ATTLIST 学生 编号 ID #REQUIRED 性别 (男|女) #REQUIRED 癖好 CDATA #IMPLIED >
对应的 xml文件:
<?xml version="1.0" encoding="utf-8" ?><班级 编号="des3" 年级="大一" 学校='西工大' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.example.org/student" xsi:schemaLocation=" http://www.example.org/student student.xsd"> <学生 编号="d3" 性别="女" > <姓名>阿娇</姓名> <年龄>50</年龄> <身高>150</身高> <体重>40</体重> </学生> <学生 编号="df3" 性别="男"> <姓名>薛鹏</姓名> <年龄>55</年龄> <身高>175</身高> <体重>70.32</体重> </学生></班级>
1.3.2. XML约束–schema 约束
schema约束:
schema和DTD的对比(面试题):
- schema符合XML的语法结构。
- DOM、SAX 可以很好地解析schema文档。
- schema对名称空间支持的好。
- schem支持更多的数据类型,自定义的数据类型。
预先定义元素和属性
- schema的后缀名是.xsd
- 必须只能有一个根节点,名称是schema。
开发步骤
- 开发schema的约束文档
- schema文档声明
<schema xmlns ="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.itcast.cn/1110"
elementFormDefault="qualified"
> 引入W3C的名称
- 在根节点上schema,使用属性xmlns (全称: xml namespace)
- xmlns=”http://www.w3.org/2001/XMLSchema”
起名:targetNamespace 目标名称空间(起名)
- 值是任意的:”http://www.itcast.cn/1110” 一般为域名
*- elementFormDefault
qualified(使用):质量好的
unqualified :质量不好的↑
- elementFormDefault
- 值是任意的:”http://www.itcast.cn/1110” 一般为域名
在XML文档中的–“根标签”—引入自己编写的schema文档
<根标签 属性1="值1" 属性2="值2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.itcast.cn/1110" xsi:schemaLocation="http://www.itcast.cn/1110 student.xsd" >
- 引入W3C名称空间,我是实例文档。注意多了个 -instance
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” (这里的xsi 是别名)
- 引入自己编写的schema的文档
xmlns=”http://www.itcast.cn/1110” xsd文档中的 targetNamespace 内容
问题:元素上不能有相同的属性名称
- 解决:起别名 :aa
技巧:在下面出现标签的概率小起别名
- 引入自己编写的schema文档的地址
schemaLocation属性是W3C提供的,如果W3C名称空间要是有别名的话,先把别名写上。
xsi:schemaLocation=”名称空间 schema文件的地址”- 名称空间的概念
- 编写完schema文档,起唯一的名称空间。
- 在编写XML文档,通过xmlns来引入名称空间。
当标签为简单标签,没有属性时,简单文本的类型可直接在 主标签中定义
表示标签名为 name,标签内内容为double 类型当标签有属性,不包含子标签时,也必须设置成complexType,
且attribute属性必须在文本类型标签extension内,<element name="name"> <complexType> <simpleContent> <extension base="string"> <attribute name="salary" type="double" use="required"></attribute> <!-- attribute位置--> </extension> </simpleContent> </complexType></element>
当标签有属性,且包含子标签时, 需要Sequence/choice/all标签,attribute标签必须在sequence结束标签和complexType标签之间,
<element name="父标签"> <complexType> <sequence> <element name="子标签1"></element> <element name="子标签2"></element> <element name="子标签3"></element> </sequence> <attribute name="身高" ></attribute> <!-- attribute位置--> </complexType> </element>
- 名称空间的概念
student.xsd<?xml version="1.0" encoding="UTF-8"?><schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/student" xmlns:tns="http://www.example.org/student" elementFormDefault="qualified"> <element name="班级" > <complexType> <sequence> <element name="学生" maxOccurs="2"> <complexType> <sequence> <element name="姓名" type="string"></element> <element name="年龄" type="int"></element> <element name="身高" type="double"> </element> <element name="体重" type="double"></element> </sequence> <attribute name="编号" type="string" use="required"> </attribute> <attribute name="性别" type="string" use="required"> </attribute> </complexType> </element> </sequence> <attribute name="编号" type="string" use="required"></attribute> <attribute name="年级" type="string" use= "required"></attribute> <attribute name="学校" type="string" ></attribute> </complexType> </element></schema>
student.xml
<?xml version="1.0" encoding="utf-8" ?><班级 编号="des3" 年级="大一" 学校='西工大' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.example.org/student" xsi:schemaLocation=" http://www.example.org/student student.xsd"> <学生 编号="d3" 性别="女" > <姓名>阿娇</姓名> <年龄>50</年龄> <身高>150</身高> <体重>40</体重> </学生> <学生 编号="df3" 性别="男"> <姓名>薛鹏</姓名> <年龄>55</年龄> <身高>175</身高> <体重>70.32</体重> </学生></班级>
1.4. XML 解析(重点)
1.4.1. 解析方式简介
- 常用的有两种?DOM和SAX
区别:
DOM解析XML
- 在内存中形成树状结构
- 缺点:如果文档过大,容易产生内存溢出的问题。
- 优点:方便做增删改的操作
SAX解析
- 基于事件驱动,边读边解析
- 优点:不会产生内存溢出问题。
- 缺点:不能做增删改操作。
(DOM4J在内存生成树状结构,但是很少出现内存溢出,故一般使用 DOM4J 解析 xml)
1.4.1.1. DOM(JAXP Crimson解析器)
DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准。DOM是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作。由于它是基于信息层次的,因而DOM被认为是基于树或基于对象的。DOM以及广义的基于树的处理具有几个优点。首先,由于树在内存中是持久的,因此可以修改它以便应用程序能对数据和结构作出更改。它还可以在任何时候在树中上下导航,而不是像SAX那样是一次性的处理。DOM使用起来也要简单得多。
1.4.1.2. SAX
SAX处理的优点非常类似于流媒体的优点。分析能够立即开始,而不是等待所有的数据被处理。而且,由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中。这对于大型文档来说是个巨大的优点。事实上,应用程序甚至不必解析整个文档;它可以在某个条件得到满足时停止解析。一般来说,SAX还比它的替代者DOM快许多。
选择DOM还是选择SAX? 对于需要自己编写代码来处理XML文档的开发人员来说, 选择DOM还是SAX解析模型是一个非常重要的设计决策。 DOM采用建立树形结构的方式访问XML文档,而SAX采用的事件模型。
各自的优点/缺点:
- DOM解析器把XML文档转化为一个包含其内容的树,并可以对树进行遍历。用DOM解析模型的优点是编程容易,开发人员只需要调用建树的指令,然后利用navigation APIs访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用DOM解析器的时候需要处理整个XML文档,所以对性能和内存的要求比较高,尤其是遇到很大的XML文件的时候。由于它的遍历能力,DOM解析器常用于XML文档需要频繁的改变的服务中。
- SAX解析器采用了基于事件的模型,它在解析XML文档的时候可以触发一系列的事件,当发现给定的tag的时候,它可以激活一个回调方法,告诉该方法制定的标签已经找到。SAX对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的tag。特别是当开发人员只需要处理文档中所包含的部分数据时,SAX这种扩展能力得到了更好的体现。但用SAX解析器的时候编码工作会比较困难,而且很难同时访问同一个文档中的多处不同数据。
1.4.1.3. JDOM
JDOM的目的是成为Java特定文档模型,它简化与XML的交互并且比使用DOM实现更快。由于是第一个Java特定模型,JDOM一直得到大力推广和促进。正在考虑通过“Java规范请求JSR-102”将它最终用作“Java标准扩展”。从2000年初就已经开始了JDOM开发。
JDOM与DOM主要有两方面不同。首先,JDOM仅使用具体类而不使用接口。这在某些方面简化了API,但是也限制了灵活性。第二,API大量使用了Collections类,简化了那些已经熟悉这些类的Java开发者的使用。
JDOM文档声明其目的是“使用20%(或更少)的精力解决80%(或更多)Java/XML问题”(根据学习曲线假定为20%)。JDOM对于大多数Java/XML应用程序来说当然是有用的,并且大多数开发者发现API比DOM容易理解得多。JDOM还包括对程序行为的相当广泛检查以防止用户做任何在XML中无意义的事。然而,它仍需要您充分理解XML以便做一些超出基本的工作(或者甚至理解某些情况下的错误)。这也许是比学习DOM或JDOM接口都更有意义的工作。
JDOM自身不包含解析器。它通常使用SAX2解析器来解析和验证输入XML文档(尽管它还可以将以前构造的DOM表示作为输入)。它包含一些转换器以将JDOM表示输出成SAX2事件流、DOM模型或XML文本文档。JDOM是在Apache许可证变体下发布的开放源码。
1.4.1.4. DOM4J(重点)
虽然DOM4J代表了完全独立的开发结果,但最初,它是JDOM的一种智能分支。它合并了许多超出基本XML文档表示的功能,包括集成的XPath支持、XML Schema支持以及用于大文档或流化文档的基于事件的处理。它还提供了构建文档表示的选项,它通过DOM4J API和标准DOM接口具有并行访问功能。从2000下半年开始,它就一直处于开发之中。
为支持所有这些功能,DOM4J使用接口和抽象基本类方法。DOM4J大量使用了API中的Collections类,但是在许多情况下,它还提供一些替代方法以允许更好的性能或更直接的编码方法。直接好处是,虽然DOM4J付出了更复杂的API的代价,但是它提供了比JDOM大得多的灵活性。
在添加灵活性、XPath集成和对大文档处理的目标时,DOM4J的目标与JDOM是一样的:针对Java开发者的易用性和直观操作。它还致力于成为比JDOM更完整的解决方案,实现在本质上处理所有Java/XML问题的目标。在完成该目标时,它比JDOM更少强调防止不正确的应用程序行为。
DOM4J是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件。如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML,特别值得一提的是连Sun的JAXM也在用DOM4J。
1.4.2. 解析
1.4.2.1. JAXP 下的 DOM 解析
解析
1. 获取 DocumentBuilderFactory(解析器工厂类)对象
public static DocumentBuilderFactory newInstance(); 获取 DocumentBuilderFactory 的新实例。
- 获取 DocumentBuilder(解析器)对象
public abstract DocumentBuilder newDocumentBuilder() (虽然是抽象方法,但多态调用子类的实现方法)使用当前配置的参数创建一个新的 DocumentBuilder 实例。
- 解析XML文档
public Document parse(String path) 解析XML文档,返回Document对象
- 根据需求获得NodeList 集合
NodeList nodeList = document.getElementsByTagName("作者");
- 遍历NodeList集合 获取每个Node内的内容
NodeList: Node item(int index); 根据下标获取NodeList集合中的Node对象 Node: String getTextContent(); 获取Node对象(标签)中的文本内容 for(int i=0;i<nodeList.getLength();i++){ Node node = nodeList.item(i); System.out.println(node.getTextContent()); }
示例:
解析XML(Document parse(String uri) ) // 获取解析器工厂类 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // 获取解析器对象 DocumentBuilder builder = factory.newDocumentBuilder(); // 解析XML的文档,返回document对象 Document document = builder.parse("src/book2.xml"); // 获取作者元素对象的集合,返回NodeList,注意返回的是NodeList(ELement的父类)而不是Element NodeList nodeList = document.getElementsByTagName("作者"); // 循环遍历,拿到每一个作者,打印文本的内容,getTextContent() for(int i=0;i<nodeList.getLength();i++){ Node node = nodeList.item(i); System.out.println(node.getTextContent()); }
//获取标签的属性值 Document doc = JaxpDomutil.getDocument("src/book1.xml"); Node node = doc.getElementsByTagName("书").item(0); NamedNodeMap attMap = node.getAttributes(); 注意这里返回的是NamedNodeMap子类对象(实际上是属性集合) System.out.println("--------------------"); System.out.println(attMap.getLength()); for(int i=0;i<attMap.getLength();i++){ Node att=attMap.item(i); node ---content System.out.println(att.getTextContent()); }
//递归得到 Node 中的所有节点名称(前序遍历) public static void getNodeName(Node node){ if(node.getNodeType() == Node.ELEMENT_NODE){ System.out.println(node.getNodeName()); } NodeList nodeList = node.getChildNodes(); for(int i=0;i<nodeList.getLength();i++){ Node child = nodeList.item(i); getNodeName(child); } }
回写
* 获取回写的工厂类
* 获取回写对象
* 调用回写的方法进行回写。
修改 document对象中的内容之后进行回写
// 创建回写类的工厂 TransformerFactory transformerFactory = TransformerFactory.newInstance(); // 获取回写类 Transformer transformer = transformerFactory.newTransformer(); // 调用回写的方法 transformer.transform(new DOMSource(document), new StreamResult("src/book2.xml"));
//将获取Document对象和 回写封装到方法中public class JaxpDomutil { public static Document getDocument(String path) throws Exception{ DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = builderFactory.newDocumentBuilder(); return builder.parse(path); } public static void writeXML(Document doc,String path) throws Exception{ TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); transformer.transform(new DOMSource(doc), new StreamResult(path)); } // 在指定的节点之前添加子节点 public static void InsertBefore(Node newNode,Node refNode){ Node parentNode = refNode.getParentNode(); parentNode.insertBefore(newNode, refNode); }}
1.4.2.2. JAXP 下的 SAX 解析
SAX的解析原理:
解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分(边读边解析)
都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,
会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
事件处理器由程序员编写,程序员通过事件处理器中方法的参数,
就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。
解析过程
1. 获取解析器的工厂
SAXParserFactory saxParseFactory = SAXParserFactory.newInstance();
- 获取解析器对象
SAXParser saxParser = saxParseFactory.newSAXParser();
- 解析XML(XML的文件的地址,事件处理器)
saxParser.parse(path,new MyHandler()); // 其中MyHandler() 继承自DefaultHandler()
事件处理器(DefaultHandler)?
自己编写的类MyHandler(),需要继承DefalutHandler类,重写三个方法。- startElement(qName) 开始标签名
- characters(char[] ch,int start,int length) 标签内部文本内容
- endElement(qName) 结束标签名
通过传进来的参数qName、char[] 、qName 获取开始标签内容、文本内容、结束标签内容
1.4.3. DOM4j
- DOM4J的解析(必须会,企业中用的多)
- 先下载DOM4J相应的jar包。导入工程中,才能使用。
- 把dom4j-1.6.1.jar导入到工程中。
- WEB项目:复制dom4j-1.6.1.jar到 WebRoot – WEB-INF – lib里面。就ok。
- Java项目:右键工程项目,选择Build Path
解析过程
1. 获取解析器对象
SAXReader saxReader=new SAXReader();
- 解析获取Document对象
Document doc = saxReader.read("src/book1.xml");
- 获取文档根结点
Element root = doc.getRootElement();
DOM4j中,获得Document对象的方式有三种:
- 读取XML文件,获得document对象
SAXReader reader = new SAXReader(); Document document = reader.read(new File("input.xml"));
- 解析XML形式的文本,得到document对象.
String text = "<members></members>"; Document document = DocumentHelper.parseText(text);
- 主动创建document对象.
Document document = DocumentHelper.createDocument(); //创建根节点 Element root = document.addElement("members");
节点方法
1. 获取文档的根节点.
Element root = document.getRootElement();
- 取得某个节点的子节点.
Element element=root.element("书名");
- 取得节点的文本内容
String text=node.getText();
- 取得某节点下所有名为“member”的子节点,并进行遍历.
List nodes = rootElm.elements("member"); -->获取所有子元素结点 for (Iterator it = nodes.iterator(); it.hasNext();) { Element elm = (Element) it.next(); // do something }
- 对某节点下的所有子节点进行遍历.
for(Iterator it=root.elementIterator();it.hasNext();){ Element element = (Element) it.next(); // do something?? }
- 在某节点下添加子节点.
Element ageElm = newMemberElm.addElement("age"); (可通过父结点root添加 List<Element> eles = root.elements(); Element newEle=DocumentHelper.createElement("age"); newEle.setText("16"); eles.add(1,newEle); -->插入子节点集合中的1位置 )
- 设置节点文字.
element.setText("29");
- 删除某节点.
parentElm.remove(childElm); //childElm是待删除的节点,parentElm是其父节点
- 添加一个CDATA节点.
Element contentElm = infoElm.addElement("content"); contentElm.addCDATA(diary.getContent());
属性方法:
attribute.getQualifiedName() getValue()/getText() 属性名 属性值
- 取得某节点下的某属性
Element root=document.getRootElement(); //属性名name Attribute attribute=root.attribute("size");
- 取得属性的文字
String text=attribute.getText();
- 删除某属性
Attribute attribute=root.attribute("size"); root.remove(attribute);
- 遍历某节点的所有属性
Element root=document.getRootElement(); 方法一:推荐 for(int i=0;i<root.attributeCount();i++){ Attribute attribute = root.attribute(i); System.out.println(attribute.getQualifiedName()+"\""+attribute.getValue+"\""); } 方法二: for(Iterator it=root.attributeIterator();it.hasNext();){ Attribute attribute = (Attribute) it.next(); String text=attribute.getText(); System.out.println(text); }
- 设置某节点的属性和文字.
newMemberElm.addAttribute("name", "sitinspring");
- 设置属性的文字
Attribute attribute=root.attribute("name"); ---> 获取属性名为 name 的属性对象 attribute.setText("sitinspring"); ---> 设置属性值
将文档写入XML
1. 文档中全为英文,不设置编码,直接写入的形式.
XMLWriter writer = new XMLWriter(new FileWriter("output.xml"));writer.write(document);writer.close();
- 文档中含有中文,设置编码格式写入的形式.
OutputFormat format = OutputFormat.createPrettyPrint(); // 指定XML编码 format.setEncoding("GBK"); XMLWriter writer = new XMLWriter(newFileWriter("output.xml"),format); writer.write(document); writer.close();
字符串与XML的转换
- 将字符串转化为XML
String text = "<members> <member>sitinspring</member></members>"; Document document = DocumentHelper.parseText(text);
2.将文档或节点的XML转化为字符串.
SAXReader reader = new SAXReader(); Document document = reader.read(new File("input.xml")); String docXmlText=document.asXML(); --> 将XML文档转换成XML格式的字符串 Element root=document.getRootElement(); String rootXmlText=root.asXML(); --> 将根结点转换成XML格式的字符串 Element memberElm=root.element("member"); String memberXmlText=memberElm.asXML(); --> 将元素结点转换成XML格式的字符串
DOM4J对XPATH的支持
- 导入包。jaxen-1.1-beta-6.jar。
怎么使用?
selectNodes(“/AAA”) 返回集合
selectSingleNode() 一个Node对象参数就是xpath的语法
/ 考虑层级关系 / / 不考虑层级关系/AAA/BBB 获取BBB的节点//AAA/BBB A不考虑层级,B考虑层级/ /BBB 无论层级关系,找到BBB的节点* 代表是所有/AAA/BBB[1] 找到BBB的第一个 /AAA/BBB[last()] 最后一个上面这种只能用单斜线 不能用双斜线@ 属性/*/*/*/BBB 代表三层标签下的 BBB标签
将文档写入XML
1.文档中全为英文,不设置编码,直接写入的形式.
XMLWriter writer = new XMLWriter(new FileWriter("output.xml")); writer.write(document); writer.close();
2.文档中含有中文,设置编码格式写入的形式.
OutputFormat format = OutputFormat.createPrettyPrint();// 指定XML编码????? ???????????? format.setEncoding("GBK"); XMLWriter writer = new XMLWriter(newFileWriter("output.xml"),format); writer.write(document); writer.close();
1.4.4. Pull解析
与Sax一样.都属于事件驱动的解析方式.
相比Sax解析过程更加灵活.
sax一旦开始解析就是从头读到尾.不解析完整个文档不会停
pull解析较为灵活.是以事件为单位.手动向下继续. 如果获得到我们要找的内容. 可以停止继续解析.
缺点:只能进行查询,不能做增删改
public static List<Student> parseXML(InputStream is) throws Exception{ //1:创建解析器工厂 XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); //2:使用工厂获得解析器 XmlPullParser parser = factory.newPullParser(); //3: 使用解析器读取XML流 parser.setInput(is, "UTF-8"); //4: 获得当前事件的状态 int type = parser.getEventType(); List<Student> list =null; Student stu = null; //5:判断当前事件状态 while(type!=XmlPullParser.END_DOCUMENT){ switch(type){ case XmlPullParser.START_TAG: if("students".equals(parser.getName())){ list = new ArrayList<Student>(); }else if("student".equals(parser.getName())){ stu = new Student(); }else if("name".equals(parser.getName())){ String name = parser.nextText(); stu.setName(name); }else if("age".equals(parser.getName())){ int age = Integer.parseInt(parser.nextText()); stu.setAge(age); }else if("height".equals(parser.getName())){ double height = Double.parseDouble(parser.nextText()); stu.setHeight(height); } break; case XmlPullParser.END_TAG: if("student".equals(parser.getName())){ list.add(stu); stu = null; } break; default: break; } //让解析器向下解析一行,并返回改行的事件常量 type = parser.next(); } return list; }
- XML解析
- xml解析
- XML解析
- 解析XML
- xml解析
- 解析xml
- 解析xml
- xml解析
- XML解析
- xml解析
- XML解析
- xml解析
- xml解析
- xml解析
- xml解析
- xml解析
- 解析xml
- XML解析
- 渐变框颜色ie9显示不正常问题
- Sequence 可持久化树套树
- 解决MyEclipse报errors running builder ‘javascript validator’ on project
- redis必杀命令:连接
- 将基类的析构函数申明为虚函数
- XML解析
- TensorFlow学习笔记(二十二) tensorflow数据读取方法总结
- c3p0数据库连接池的使用
- http 与 https之间的区别
- 类的加载机制
- python数组过滤,输出满足条件的元素,例如python输出一维矩阵中的非0元素
- Android之SQLite数据库
- .NET Core资源汇总
- Spring 注解区别以及应用