JAVA EE(六)—— XML(XML文件概述、XML文件的约束、XML文件的解析、XML的反射)

一、XML文件概述

1、XML文件

(1)介绍

  • 可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。XML 的设计宗旨是传输数据,而不是显示数据。
  • XML文件可以直接使用解析器解析(IE浏览器)。

(2)作用

  • 用于存放数据
  • 用于配置文件

(3)基本语法
① 文档声明

<?xml version="1.0" encoding="utf-8" standalone="no" ?>
  • 文档声明必须以<?xml开头,以?>结束,中间没有空格,? 表示开始或者结束;
  • 文档声明必须从文档的0行0列位置开始;
  • xml 表示文件是xml格式,文件后缀是.xml;
  • 文档声明只有两个属性,格式:属性名=“属性值”,属性值必须使用"";
  • version 指定XML文档版本。必须属性,目前只有1.0版本;
  • encoding 表示指定当前文档的编码。可选属性,默认值为UTF-8;
  • standlone 表示文件是否独立,yes表示是,no表示不是。

2、XML 文件示例

<?xml version="1.0" encoding="utf-8" ?>
<中国>
	<重庆>
		<江北>江北</江北>
		<渝北>渝北</渝北>
	</重庆>
	<四川>
		<成都>成都</成都>
		<南充>南充</南充>
	</四川>
</中国>

② 元素(Element)和标签(Tag)

  • 以尖括号括起来的就是元素(和html一致,但所有的标签名可以自定义)
  • 元素体可以写也可以不写
  • 元素体里面可以是文本也可以写其他标签
  • 元素命名:
    区分大小写
    不能使用空格,冒号第特殊字符
    不建议以XML、xml、Xml开头
  • 格式化良好的xml文档,必须只有一个根元素

③ 属性(attribute):

  • 属性是元素的一部分,写在开始标签的尖括号里面,并且多个属性用空格隔开
  • 属性的定义格式:属性名=“属性值”,其中属性值必须使用单引号或双引号
  • 一个元素可以有0-N个属性,但一个元素中不能出现同名属性
  • 属性名不能使用空格、冒号等特殊字符,且必须以字母开头

④ 注释

<!-- 注释内容 -- >

⑤ CDATA区

  • 原始数据,将所有的内容都作为原始数据。
  • 语法:<![CDATA][需要转译的字符]>

⑥ 转义字符:

&lt; < 小于
&gt; > 大于
&amp; &
&apos; 单引号
&quot; " 双引号

⑦ 指令:引入标签 xml-stylesheet
如:在一个xml中引入css文件:

<?xml-stylesheet type="text/css" href="css文件名.css" ?>

二、XML文件的约束

1、约束概述

(1)介绍

  • 按照一定的规则编写xml文件,指定位置只能存放固定的标签。

(2)DTD 约束

<!ELEMENT 根标签名 (数据类型或者子标签,如果标签名是相同的(标签+))>
<!ELEMENT 父标签名 (子标签名不同的情况下,直接列举,中间用逗号隔开)>
<!ELEMENT 子标签名 (#PCDATA)>
引入DTD约束:
<!DOCTYPE 根标签名 SYSYTEM "引入的文件">

(3)三种DTD约束

  • 内部DTD,在XML文档内部嵌入DTD,只对当前XML有效
  • 外部DTD-本地DTD,DTD文档在本地系统上,公司内部自己项目使用
  • 外部DTD-公共DTD,DTD文档在网络上,一般由框架提供

2、DTD 约束示例

xml文件导入约束
① xml文件

<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<!DOCTYPE 信息 SYSTEM "users.dtd">
<信息>
	<用户>
		<姓名>张三</姓名>
		<性别></性别>
		<年龄>12</年龄>
	</用户>
	<用户1>
		<姓名>李四</姓名>
		<性别></性别>
		<年龄>23</年龄>
	</用户1>
</信息>

② dtd 约束文件

<!ELEMENT 信息 (用户+)>
<!ELEMENT 用户 (姓名,性别,年龄)>
<!ELEMENT 姓名 (#PCDATA)>
<!ELEMENT 性别 (#PCDATA)>
<!ELEMENT 年龄 (#PCDATA)>

IE浏览器默认关闭了校验文件,需要使用脚本文件将其打开:

  • 创建IE浏览器中的ActiveXObject对象,使用其对象中的控件(Microsoft.XMLDOM);
  • 设置validateOnParse变量的值为false;
  • 读取要校验的xml文件:load(“xml文件”)。
<html>
	<head>
		<script>
			var xmldom = new ActiveXObject("Microsoft.XMLDOM");
			xmldom.validateOnParse = true;
			xmldom.load("users.xml");
			//输出错误原因和行数
			document.write(xmldom.parseError.reason+"<br />");
			document.write(xmldom.parseError.line);
		</script>
	</head>
	<body>
	</body>
</html>

三、XML文件的解析

1、XML文件解析概述

(1)介绍
在java中提供了三种解析xml文件的开发包: JAXP Jdom dom4j,后面两个其实可以合成一个。

2、DOM 解析

(1)介绍

  • DOM解析方式属于JAXP开发包:DocumentBuilderFactory抽象类
  • DOM解析首先将一个xml文件中的内容全部解析到内存中,然后在内存中构建Document树。
  • 标签解析为Element,属性解析为 attr,内容解析为 text,但不管是属性或者是标签或者是文本内容都会解析为Node节点。

(2)优缺点
优点:元素与元素之间保留结构关系,可以进行增删改查操作,其查询比较快;
缺点:占用内存,XML文档过大时,可能出现内存溢出现象;

(3)DOM 解析过程:
① 创建解析xml文件的工厂:DocumentBuilderFactory 对象;
② 根据获取的工厂得到解析xml文档的解析器:DocumentBuilder 对象;
③ 获取解析器,真正开始解析xml文件:使用对象调用parse方法解析xml文档。

DocumentBuilderFactory factory= DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File("文件路径")); 

④ 解析节点属性名、节点属性值
对于节点个数未知

获取所有节点的集合
Nodelist klist = document.getElementByTagName("节点");
使用for循环通过item()方法遍历每个节点
Node node= list.item(i);
并获取节点的所有属性集合
NameNodeMap attrs = node.getAttribute();
使用for循环通过item()方法遍历节点的属性
Node attr = attrs.item(j);
获取属性名
attr.getNodeName();
获取属性值
attr.getNodeValue();

对于已经找到book节点只有一个ID属性可用以下方法,使用强制类型转换

Element node= (Element) list.item(i);
String attrValue = node.getAttribute("属性名");
获取id属性的属性值:attrValue;

⑤ 解析子节点名、子节点值

Nodelist childNodes = node.getChildNodes();
遍历childNodes获取每个节点的节点名和节点值,其中节点中包括空格和换行符
使用for循环遍历
区分text类型和element类型的node,通过getNodeType();
childNodes.item(k).getNodeType() == Node.ELEMENT_NODE
childNodes.item(k).getNodeName();
获取子节点的节点值
需要先获取book子节点,然后获得子节点的子节点的节点值
chileNodes.item(k).getFirstChild().getNodeValue(); 

getNodeValue()getTextContent() 的区别

ChildNodes.item(i).getFirstChild().getNodeValue()与ChildNodes.item(i).getTextContent()的
区别:子节点中还包含其他子节点时,后者可以把子节点的值都显示出来。
getTextContent() 获取节点中的text内容(即节点值).
getNodeType()有text、element、attr三个
而Element如果要获取值,必须读取它的子节点,<name>content</name>认为content是name的子节点;
两种方法:
getFirstChild().getNodeName();(获取子节点再获取值)
getTextContent();(获取content方法)

⑥ 将内存中的xml修改的数据更新到文件中,使用Transformer()。

//将修改后的数据写到文件中
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer former = transFactory.newTransformer();
former.transform(new DOMSource(document), new StreamResult(new File(file)));

(4)DOM解析增删改查示例

public class XMLDemo1 {
	public static void main(String[] args) throws Exception {
		XMLDemo1 xml1 = new XMLDemo1();
		xml1.read1();
		//xml1.read2();
		//update()
		//delete()
		//add()
	}
	//定义一个方法,获取标签中的文本内容(查询)
	public void read() throws Exception {
		//获取工厂
		DocumentBuilderFactory factory= DocumentBuilderFactory.newInstance();
		//根据工厂,获取解析器
		DocumentBuilder builder = factory.newDocumentBuilder();
		//调用parse开始解析xml文件
		Document document = builder.parse(new File("D:\\JAVA.Document\\xml文件\\users.xml")); 
		
		//获取节点
		NodeList list = document.getElementsByTagName("姓名");
		//获取标签节点
		Node node = list.item(0);
		//获取标签中的文本内容
		String userName = node.getTextContent();
		System.out.println(userName);
	}
	//定义一个方法,获取标签中的id属性的值(查询)
	public void read2() throws Exception {
		//获取工厂
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		//获取解析器
		DocumentBuilder builder = factory.newDocumentBuilder();
		//解析xml文件
		Document document = builder.parse(new File("D:\\JAVA.Document\\xml文件\\users.xml"));
		//获取节点
		NodeList list = document.getElementsByTagName("姓名");
		//获取标签节点
		Element node = (Element)list.item(0);
		String text = node.getAttribute("id");
		System.out.println(text);
	}
	//更改
	public void update() throws Exception{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document document = builder.parse(new File("src/users.xml"));
		//现获取内容的父节点,再修改值
		NodeList list = document.getElementsByTagName("姓名");
		Node node = list.item(0);
		//这种修改只是修改了内存中的对象,没有将修改后的数据写入到文件中
		node.setTextContent("张三");
		//将修改后的数据写到文件中
		TransformerFactory transFactory = TransformerFactory.newInstance();
		Transformer former = transFactory.newTransformer();
		former.transform(new DOMSource(document), new StreamResult(new File("src/users.xml")));
	}
	//删除
	public void delete() throws Exception {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document document = builder.parse(new File("src/users.xml"));
		
		//获取节点
		Node node = document.getElementsByTagName("身高").item(0);
		//删除节点:只能先获取父节点,再删除自己
		node.getParentNode().removeChild(node);
		
		//将修改后的数据写到文件中
		TransformerFactory transFactory = TransformerFactory.newInstance();
		Transformer former = transFactory.newTransformer();
		former.transform(new DOMSource(document), new StreamResult(new File("src/users.xml")));
	}
	//增加
	public void add()  throws Exception {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document document = builder.parse(new File("src/users.xml"));
		
		Element node = document.createElement("用户");
		//得到父节点
		Node parentNode = document.getElementsByTagName("信息").item(0);
		//用户挂载到信息
		parentNode.appendChild(node);
		Element nameNode = document.createElement("姓名");
		nameNode.setTextContent("王五");
		node.appendChild(nameNode);
	}
}

3、SAX 解析

(1)SAX解析与DOM解析的差异

  • 在使用 DOM 解析 XML 文档时,需要读取整个 XML 文档,在内存中构架代表整个 DOM 树的Doucment对象,从而再对XML文档进行操作。此种情况下,如果 XML 文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。
  • SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作。从xml文件的最上面开始逐一解析每一个节点,可以对于每一个节点做出其处理方式,逐一解析到内存中,寻找到符合要求的节点则结束解析。

(2)SAX解析优缺点
优点:处理速度快,可以处理大文件,节省内存。
缺点:只能读,逐行解析后将释放资源,其查询比较慢。

(3)SAX解析步骤:
① 创建SAX解析工厂、解析器对象、XML的读取器

SAXParserFactory spf = SAXParserFactory.newInstance();       
SAXParser sp = spf.newSAXParser();
XMLReader xmlReader = sp.getXMLReader();

② 设置读取器的事件处理器、解析xml文件

xmlReader.setContentHandler(new BookParserHandler());  
xmlReader.parse("xml文件路径");

③ 创建 ParserHandler 的类

并且重写startDocument、endDocument、startElement、endElement的方法
startDocument:解析xml文件的标签开始
endDocument:解析xml文件的标签开始
startElement:解析xml文件开始
endElement:解析xml文件开始
characters:解析xml节点属性
可以定义全局变量int index = 0;为在main中设置解析每本书

④ 解析xml文件的节点属性

调用startElement(String url,String localName,String qName,Attributes attributes)方法;
开始解析book元素的属性
if(qName.equals("book")){
	//已知book元素下属性名称,根据属性名称获取属性值
	String value = attributes.getValue("id");
	//不知道book元素下属性名和个数,可以使用for循环遍历book下属性
	属性名:attributes.getQName(i);
	属性值:attributes.getValue(i);
}
判断解析book是否结束
在endElement方法中使用
if(qName.equals("book")){
	结束该本书的解析 
}

⑤ 解析xml文件的节点名和节点间文本

解析文件的节点名,可以判断
if(!qName.equals("book")&&!qName.equals("bookstore")){
	打印出解析节点值
}
	
新建Characters方法
public void characters(char[] ch, int start, int length){
	String value = new String(ch, start, length);
	if(!value.trim().equals("")){//去掉文本后的空格
		value;//可以得到节点值
	}
}

⑥ 使用xml解析将xml的内容和结构存入Java对象

新建book类,创建所有属性,并创建get和set方法
并在解析book值时,将得到的属性值set进book的方法中。

4、DOM4J解析

(1)DOM4J解析示例
① DOM4J 解析节点

解析books.xml文件
(1)创建SAXReader的对象reader   
SAXReader reader = new SAXReader();
(2)通过reader对象的read方法加载book.xml文件,获取document对象
Document document = reader.reader(new File("src/res/book.xml"));
(3)通过document对象获取根节点bookstores
Element bookStore = document.getRootElement();
(4)通过element独享的elementIterator方法获取迭代器
Iterator it = bookStore.elementIterator();
(5)遍历迭代器,获取根节点中的信息(书籍)
while(it.hasNext()){
	Element book = (Element)it.next();
	获取book的属性名和属性值
	List<Attribute>bookAttrs = book.attribute();
	遍历每本书中的所有节点
	for (Attribute attr : bookAttrs){
		获取属性名
		attr.getName(); 
		获取属性值
		attr.getValue();
	}
}

② DOM4J 解析子节点信息

遍历book子节点依然可以使用elementIterator方法获取迭代器
Iterator itt = book.elementIterator(); 
while(itt.hasNext()){
	Element bookChild = (Element)itt.next();
	获取节点名
	bookChild.getName(); 
	获取节点值
	bookChild.getStringValue();      
}

5、JDOM 解析

(1)JDOM 解析步骤
① 导入jar包

② 准备工作

(1)创建一个SAXBuilder对象
SAXBuilder saxBuilder = new SAXBuilder;
(2)创建一个输入流,将xml文件加载到输入流
InputStream in = new FileInputStream("src/res/books.xml");
(3)通过saxBuilder的build方法,将输入流加载到saxBuilder
Document document = saxBuilder.build(in);
(4)通过document对象获取xml的根节点
Element rootElement = document.getRootElement();
(5)获取根节点下的子节点的List集合
List<Element> bookList = rootElement.getChildren();

③ 解析节点属性

(1)采用for循环遍历bookList中每个元素
for(Element book : bookList){
	bookList.indexof(book);可以获取当前该本书处于bookList中的位置
}  
(2)解析book的属性
List<Attribute> attrList = book.getAttributes();
遍历attrList(针对不清楚book节点下属性的名字及数量)

   book.getAttributeName("");
   book.getAttributeValue("属性名");
   用以上两种方法可以获取已知的节点属性名和属性值
        
   for(Attribute attr : attrList){
	获取属性名
	String attrName = attr.getName();
	获取属性值
	String attrValue = attr.getValue();
   }
(3)解析子节点名和子节点值
List<Element> bookChilds = book.getChildren();
遍历bookChilds 
for (Element child : bookChilds ){
	child.getName();
	child.getValue();
}

④ 解析时乱码的处理

(1)encoding编解码方式更改
(2)(1)无法解决时
在创建输入流时可以改为使用InputStreamReader( ,"UTF-8");
通过使用字符流的方式

⑤ JDOM中存储Book对象

(1)创建book对象
Book bookEntity = new Book();

(2)判断id属性
if(attrName.equals("id")){
	bookEntity.setId(attrValue)
}

(3)判断属性名
if(child.getName().equals("name")){
	bookEntity.setName(child.getValue());
}
通过以上方法对每一个属性都进行判断

(4)创建一个ArrayList来存储对象
private static ArrayList<book> booksList = new ArrayList<book>();
booksList.add(bookEntity);
bookEntity = null;

⑥ JDOM中jar包的引用
若按之前的操作,有可能会发生由于工程的导入导出操作导致jar丢失,此时可以按一下操作解决。
在package下new一个folder,然后将放在桌面的jar包复制进刚刚new的folder中去,然后在package中继续build path,然后选中刚刚复制的jar 包。

6、几种解析方法比较

(1)解析方法分类

  • 基础解析方式:DOM、SAX
  • 扩展解析方式:JDOM、DOM4J

(2)DOM解析过程:

  • 一次性将整个xml文件加载到内存中,形成DOM树
  • 优点:形成了树结构,直观好理解,代码更容易编写解析过程中树结构保留在内存中,方便修改
  • 缺点:当xml文件较大时,对内存消耗比较大,容易影响解析性能并造成内存溢出

(3)SAX解析过程:

  • 逐条语句判断解析(基于时间的解析方式)
  • 优点:采用事件驱动模式,对内存消耗比较小适用于只需要处理xml中数据时
  • 缺点:不易编码,很难同时访问同一个xml中的多处不同数据

(4)JDOM解析过程:

  • 仅使用具体类而不使用接口
  • API大量使用了Collections类

(5)DOM4J解析过程:

  • JDOM的一种智能分支,它合并了许多超出基本XML文档表示的功能
  • DOM4J使用接口和抽象基本类方法,一个优秀的Java XML API具有性能优异、灵活性好、功能强大和极端易使用的特点,
  • 是一个开放源代码的软件

四、XML的反射

1、反射介绍

  • 获取对象类,并解析出其组成部分(方法,属性,构造方法)。
  • Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。
  • 使用反射,可以在运行时对类Class、构造方法Constructor、普通方法Method、字段Field进行操作。

2、Class 对象
(1)getConstructor():获取一个类的公共的构造方法

  • 获取无参构造:getConstructor(null);
  • 获取有参构造:getConstructor(数据类型.class);

调用到构造方法之后,想要使用反射创建对象,那么就必须使用newInstance()方法,有参就需要传递参数,无参则不需要。

(2)getMethod():获取一个类的公共的成员方法

  • 无参的方法:getMethod(null); 想要调用方法,需要使用invoke(对象, null); 方法
  • 有参的方法:getMethod(方法名, 数据类型.class);想要调用方法,需要使用invoke(对象, 参数列表); 方法

(3)getField():获取一个公共的成员属性

Field field = clazz.getField("成员属性名"); 

想要使用到该属性,使用field.get(对象)方法获取其数据,field.set()能够设置数据,如果是final成员属性,需要使用setAccessible(true); 暴力破解

(4)getDeclaredConstructor():获取一个类的私有的构造方法
(5)getDeclaredMethod():获取一个类的私有的成员方法
(6)getDeclaredField():获取一个私有的成员属性
(4)、(5)、(6)都需要使用setAccessible(true);暴力破解

(7)使用反射创建字节码
方式1:Class cla = Class.forName(“完整类名”);完整类名是指:包名.类名

Class clazz = Class.forName("com.study.Person");//必须类全名

方式2:Class cla = 类名.class;

Class clazz = Person.class;

方式3:Class cla = new 类名().getClass();

	//创建Peron对象
	Person p = new Person();
	//通过object继承来的方法(getClass)获取Person对应的字节码文件对象
	Class clazz = p.getClass();

(8)反射示例
示例1:反射操作构造方法
① Person类

	public class Person {
		public String name;
		private int age;
		public Person() {
			System.out.println("这是无参构造");
		}
		public Person(String name) {
			System.out.println(name + "这是有参构造");
		}
		public Person(String name, int age) {
			System.out.println(name + "说这是有参构造,今年" + age + "岁");
		}
		private Person(int age) {
			System.out.println("私有构造方法" + age);
		}
		public void eat() {
			System.out.println("吃饭");
		}
		public void eat(String name) {
			System.out.println(name + "吃饭");
		}
		private void sleep() {
			System.out.println("睡觉");
		}
	}

② main函数类

public class Demo {
	@Test
	public void refect1() throws Exception{	//调用无参构造
		//1、使用反射,获取字节码对象
		Class cla = Class.forName("javaeestudy.num1.Person");
		//2、使用Class类中的getConstructor()方法,调用其类的公共无参构造方法
		Constructor constructor = cla.getConstructor(null);
		constructor.newInstance();
	}
	
	@Test
	public void refect2() throws Exception{	//调用有参构造
		//1、使用反射,获取字节码对象
		Class cla = Class.forName("javaeestudy.num1.Person");
		//2、使用Class类中的getConstructor()方法,调用其类的公共有参构造方法
		Constructor constructor = cla.getConstructor(String.class);
		constructor.newInstance("张三");
	}
	
	@Test
	public void refect3() throws Exception{	//调用有参构造
		//1、使用反射,获取字节码对象
		Class cla = Class.forName("javaeestudy.num1.Person");
		//2、使用Class类中的getConstructor()方法,调用其类的公共有参构造方法
		Constructor constructor = cla.getConstructor(String.class, int.class);
		constructor.newInstance("张三", 18);
	}
	
	@Test
	public void refect4() throws Exception{	//调用私有构造方法
		//1、使用反射,获取字节码对象
		Class cla = Class.forName("javaeestudy.num1.Person");
		//2、使用Class类中的getConstructor()方法,调用其类的私有构造方法
		Constructor constructor = cla.getDeclaredConstructor(int.class);
		//3、开启暴力破解
		constructor.setAccessible(true);
		constructor.newInstance(18);
	}
}

示例2:反射对方法和属性的操作

public class Demo2 {
	@Test
	public void method1() throws Exception {	//使用反射操作其类中的方法
		Class cla = Class.forName("javaeestudy.num1.Person");
		//参数(name, parameter),name表示方法名,parameter表示参数的数据类型
		Method method = cla.getMethod("eat", null);
		//invoke(obj, args)方法,使用对象调用方法,obj表示对象,args表示参数值
		method.invoke(cla.newInstance(), null);
	}
	@Test
	public void method2() throws Exception {	//操作有参方法
		Class cla = Class.forName("javaeestudy.num1.Person");
		//参数(name, parameter),name表示方法名,parameter表示参数的数据类型
		Method method = cla.getMethod("eat", String.class);
		//invoke(obj, args)方法,使用对象调用方法,obj表示对象,args表示参数值
		method.invoke(cla.newInstance(), "张三");
	}
	@Test
	public void method3() throws Exception {	//操作私有方法
		Class cla = Class.forName("javaeestudy.num1.Person");
		//参数(name, parameter),name表示方法名,parameter表示参数的数据类型
		Method method = cla.getDeclaredMethod("sleep", String.class);
		//开启暴力拆解
		method.setAccessible(true);
		//invoke(obj, args)方法,使用对象调用方法,obj表示对象,args表示参数值
		method.invoke(cla.newInstance(), "张三");
	}
	@Test
	public void method4() throws Exception {	//操作公共属性
		Class cla = Class.forName("javaeestudy.num1.Person");
		Field field = cla.getField("name");
		//获取字段的值
		//obj参数,代表的是那个对象的字段
		String obj = (String) field.get(cla.newInstance());
		System.out.println(obj);
	}
	@Test
	public void method5() throws Exception {	//操作公共属性
		Class cla = Class.forName("javaeestudy.num1.Person");
		Field field = cla.getDeclaredField("age");
		//开启暴力拆解
		field.setAccessible(true);
		//获取字段的值
		//obj参数,代表的是那个对象的字段
		int age = field.getInt(cla.newInstance());
		System.out.println(age);
	}
}

示例3:通过操作xml文件和反操作方法
① xml文件

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<package pname="javaeestudy.study">
	<clazz cname="Person">
		<method type="public">eat</method>
		<method type="private">sleep</method>
	</clazz>
</package>

② Person类

public class Person {
	//公共方法
	public void eat() {
		System.out.println("吃饭");
	}
	//私有方法
	private void sleep() {
		System.out.println("睡觉");
	}
}

③ main函数:操作类

public class Demo {
	public static void main(String[] args) throws Exception {
		new Demo2().method1();
	}
	//操作方法
	public void method1() throws Exception {
		Document document = getDocument();
		//获取包名
		NodeList packageList = document.getElementsByTagName("package");
		Element packageNode = (Element)packageList.item(0);
		String text = packageNode.getAttribute("pname");
		
		//获取类名
		NodeList clazzList = document.getElementsByTagName("clazz");
		Element clazzNode = (Element)clazzList.item(0);
		text = text + "." + clazzNode.getAttribute("cname");

		//使用反射,获取字节码对象
		Class cla = Class.forName(text);
		
		//获取方法节点
		NodeList methodList = document.getElementsByTagName("method");
		
		for(int i = 0; i < methodList.getLength(); i++) {
			//获取方法类型type
			Element typeNode = (Element)methodList.item(i);
			String typeText = typeNode.getAttribute("pname");
			//获取方法名
			Node methodNode = methodList.item(i);
			String methodName = methodNode.getTextContent();
			
			Method method = null;
			if(typeText.equals("public")) {
				//使用Class类中的getMethod方法,调用其类的公共无参构造方法
				method = cla.getMethod(methodName, null);
			}else {
				//使用Class类中的getDeclaredMethod方法,调用其类的私有无参构造方法
				method = cla.getDeclaredMethod(methodName, null);
				//开启暴力拆解
				method.setAccessible(true);
			}
			//invoke(obj, args)方法,使用对象调用方法,obj表示对象,args表示参数值
			method.invoke(cla.newInstance(), null);
		}
	}
	//获取document方法
	public Document getDocument() throws Exception {
		//获取工厂
		DocumentBuilderFactory factory= DocumentBuilderFactory.newInstance();
		//根据工厂,获取解析器
		DocumentBuilder builder = factory.newDocumentBuilder();
		//调用parse开始解析xml文件
		return builder.parse(new File("src\\javaeestudy\\study\\person.xml"));
	}
}
发布了104 篇原创文章 · 获赞 58 · 访问量 7510

猜你喜欢

转载自blog.csdn.net/baidu_27414099/article/details/104440878