文章目錄
一、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][需要轉譯的字符]>
⑥ 轉義字符:
< |
< | 小於 |
---|---|---|
> |
> | 大於 |
& |
& | 和 |
' |
’ | 單引號 |
" |
" | 雙引號 |
⑦ 指令:引入標籤 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"));
}
}