npm安裝與webpack的下載
反射:在類執行時,能夠動態獲取並訪問其構造結構的機制稱為反射機制。
反射是Java中框架設計的核心,通過對類的構造、屬性、方法等資料的獲取提供抽象的底層構建
反射機制:
反射需要先獲得類的class位元組碼,由JVM類載入器(ClassLoader)負責載入,並在記憶體中快取class的內部結構。藉助於Java的反射機制允許快速對類的結構資料進行訪問和呼叫
獲得class位元組碼檔案的三種方式:
1.Object物件的getClass()方法
獲得方式一
Class<User> userClass = (Class<User>) user.getClass();
2.類的class靜態屬性(一個類只有一個class,例項化多次對應的都是同一個class,所以class可以用==進行比較,a.getClass==b.getClass)
獲得方式二 Class<User> userClass = User.class;
3.Class.forName(String classPath)的載入(反射應用的核心)
獲得方式三 通過類路徑訪問類的Class資訊,在不知道型別的情況下,可以不寫泛型
Class<User> userClass = (Class<User>) Class.forName("com.igeek.pojo.User");
反射允許獲取到類的各種構造結構,包括構造方法、方法、屬性、介面、註解等
反射能夠對類完成例項構建,並能對方法進行例項呼叫
第三種方法的使用:
Class objClass = Class.forName(“com.igeek.pojo.User”)
Object obj = objClass.newInstance()
獲取類的構造方法
getConstructor(Class<T>… parameterTypes)
getConstructors()
獲取類的屬性
getField(String fieldName)
getFields()
獲取類的方法
getMethod(String methodName,Class<T>…parameterType) getMethods()
獲取類的介面
getInterfaces()
獲取類的超類
getSuperclass()
XML
Extensible Markup Language 可擴充套件標記語言
作用:
1.用於對工程進行外部配置
2.用於描述複雜格式的資料,對資料進行儲存管理
3.用於跨應用進行資料的互動
每一個XML檔案都以標籤的方式進行編寫,並且必須要有一個跟標籤
XML中每個標籤都稱為節點或元素,標籤體的文字也是節點元素,稱為文字節點
定義根標籤:使用DTD或者是Schema檔案來定義XML的內容
解析XML文件主要有兩種方式:
1.DOM解析
特點: 將整個XML文件全部載入至記憶體中,在記憶體中對文件進行解析
2.SAX解析
特點:使用事件驅動方式進行解析,一邊讀取一邊解析
DOM解析的使用步驟:
1.DOM4j架包匯入:
File——Project Structures——Libraries——選擇DOM所在的位置——OK
2.建立XML
Setting——Editor——File and Code templates——"+"——名稱為“new.xml”——輸入“<?xml version="1.0" encoding="UTF-8"?>”——單擊"OK"
3.新建檔案
新建檔案進行new一個new.xml檔案
MyInterfaceA
package com.igeek; public interface MyInterfaceA { }
MyInterfaceB
package com.igeek; public interface MyInterfaceB { }
Human類
package com.igeek.pojo; public class Human { public int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
User類
package com.igeek.pojo; import com.igeek.MyInterfaceA; import com.igeek.MyInterfaceB; //實現了A、B兩個介面,繼承了Human類 public class User extends Human implements MyInterfaceA, MyInterfaceB { //三個屬性 private int userId; private String userName; public String password; //空參構造方法 public User() { } //帶參構造方法 public User(int userId, String userName, String password) { this.userId = userId; this.userName = userName; this.password = password; } //屬性的get 、set方法 public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
獲取類的方法
package com.igeek; import com.igeek.pojo.Human; import com.igeek.pojo.User; /** * 獲得class檔案 * 反射是基於Class型別訪問的 * Class物件封裝快取了類的資料結構 */ public class Demo1 { public static void main(String[] args) { User user = new User(); Human human = new User(); //獲得方式一:返回值為Class,不寫泛型預設為object型別,寫了泛型就要進行強轉 //將類例項化以後對物件進行獲取class處理 Class<User> userClass = (Class<User>) user.getClass(); //獲得方式二:不用對類進行例項化,直接對類進行獲取class處理 Class<User> userClass = User.class; //獲得方式三 通過類路徑訪問類的Class資訊 try { //這個方法是因為:這個方法是可以在不明確型別和其結構時使用,
(第一個方法都已經將物件例項化出來了,不需要使用反射。) Class<User> userClass = (Class<User>) Class.forName("com.igeek.pojo.User"); } catch (ClassNotFoundException e) { e.printStackTrace(); } //上面兩種(第一種和第二種獲取class方法)方式主要用於多型場景下的型別匹配
if(human instanceof User){ System.out.println("human的例項型別是user型別"); } if(human.getClass() == User.class){ System.out.println("human的例項型別是user型別"); } } }
第三種獲取class方法的應用:
package com.igeek; import com.igeek.pojo.User; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * 使用反射解析類的資料結構 */ public class Demo2 { public static void main(String[] args) { try { //獲得類的Class物件(第三種方法),該物件封裝了類的資料結構資訊 Class objClass = Class.forName("com.igeek.pojo.User"); //使用反射將類進行例項化 //該方式只能通過類的無參構造進行例項化 Object obj = objClass.newInstance(); System.out.println("例項化後的結果:"+obj); //獲得類的所有的構造方法:返回值是構造方法的陣列 構造方法的型別是Constructor型別 Constructor[] constructors = objClass.getConstructors();
//可獲得私有的構造方法
Constructor[] constructors=ObjClass.getDeclareConstructors(); System.out.println("該類有"+constructors.length+"個構造方法"); //遍歷所有的構造 for (Constructor constructor : constructors) { System.out.println("\n-----------------------------"); //獲得構造方法的引數數量 int paramCount = constructor.getParameterCount(); System.out.println("構造方法的引數數量:"+paramCount); //獲得構造方法的引數型別 Class[] paramClassArray = constructor.getParameterTypes(); for (Class paramClass : paramClassArray) { System.out.print(paramClass.getName()+"\t"); } } System.out.println(); //根據引數獲得指定的構造方法 //獲得無參的構造 Constructor constructor1 = objClass.getConstructor(); System.out.println(constructor1); //根據構造方法來例項化物件 Object obj1 = constructor1.newInstance(); System.out.println(obj1); //獲得帶參構造方法:通過引數的class獲取指定的構造方法
//基本型別和包裝類的class是不同的 Constructor constructor2 = objClass.getConstructor(int.class,String.class,String.class); //使用帶參的構造方法例項化物件
//可以用Object接收
Object obj2=constructor2.newInstance(100,"tom","123");
//也可強轉後用User接收 User user = (User) constructor2.newInstance(100,"tom","123"); System.out.println(user.getUserId()+"\t"+user.getUserName()+"\t"+user.getPassword()); //獲得當前類的父類 Class superClass = objClass.getSuperclass(); System.out.println("\n------------父類------------");
//若結果是Object則這個類沒有手動進行extends繼承 System.out.println(superClass); //獲取實現的介面 Class[] interfaceClasses = objClass.getInterfaces(); System.out.println("\n---------實現的介面---------"); for (Class interfaceClass : interfaceClasses) { System.out.println(interfaceClass.getName()); }
//獲得屬性 //訪問當前允許訪問(具有訪問許可權)到的屬性,包括父類繼承得到的屬性
(不同包中加了protect或者加了private或者沒加訪問修飾符的都沒有訪問許可權) Field[] fields = objClass.getFields(); //訪問當前類(本類)直接宣告的屬性,不論訪問修飾符是什麼 Field[] fields = objClass.getDeclaredFields(); System.out.println("\n------------屬性-------------"); for (Field field : fields) { //獲得屬性的名稱 System.out.println("屬性名稱:"+field.getName()); //獲得屬性的型別 System.out.println("屬性型別:"+field.getType()); } System.out.println("\n-------------------------------"); //獲得指定名稱屬性 Field nameField = objClass.getDeclaredField("userName"); //為屬性提供訪問許可權,即使是私有屬性也將允許訪問處理 nameField.setAccessible(true); //對屬性進行賦值,第一個引數表示該屬性從屬的物件,第二個引數表示要設定的值 //set方法允許對屬性進行賦值,但是會根據屬性本身的訪問修飾符來決定是否可以成功操作
(paivate時不能被set,但是setAccessible後即可不管是什麼訪問修飾符都可以進行設定可以訪問處理) nameField.set(user,"jack"); //System.out.println(user.getUserName()); //獲取屬性的值 Object value = nameField.get(user); System.out.println(value); System.out.println("--------------方法的訪問-------------");
//獲取所有方法,包括私有的
Method[] methods=objClass.getDeclareMethods();
//獲取所有方法 Method[] methods = objClass.getMethods(); for (Method method : methods) { //獲取方法的名稱 System.out.println("方法名:"+method.getName()); //獲取返回值型別 Class returnClass = method.getReturnType(); System.out.println("返回值型別:"+returnClass); //獲取方法的引數型別 Class[] paramClassArray = method.getParameterTypes(); System.out.println("方法的引數:"); for (Class paramClass : paramClassArray) { System.out.println(paramClass); } System.out.println("------------------"); } //獲取一個指定名稱的方法:第一個引數是方法的名稱,第二個引數是引數的型別,可以多個可以一個可以沒有 Method setMethod = objClass.getMethod("setUserName", String.class); //使用反射呼叫方法(修改原內容):第一個引數是代表修改的哪個物件中的內容,第二個引數是要修改成的值 setMethod.invoke(user, "admin"); Method getMethod = objClass.getMethod("getUserName"); //呼叫方法(獲得返回值):返回值是Object型別,如果呼叫的方法沒有返回值,則返回的值null Object returnValue = getMethod.invoke(user); System.out.println("返回值是:"+returnValue); } catch (Exception e) { e.printStackTrace(); } } }
例子:
使用反射動態解析javax.swing.JFrame類
使用反射例項化該物件
使用反射動態解析該類的構造方法,獲得構造方法的引數數量和型別
並使用無參構造以及帶有String的構造
方法來例項化JFrame物件
package Demo1; import java.lang.reflect.Constructor; public class Demo { public static void main(String[] args) { //獲取類方法 try { Object objClass=Class.forName("javax.swing.JFrame"); //使用反射例項化該物件 Object obj=((Class) objClass).newInstance(); System.out.println("例項化後的物件是:"+obj); //使用反射動態解析該類的構造方法,獲得構造方法的引數數量和型別 Constructor[] constructors=((Class) objClass).getConstructors(); System.out.println("共有"+constructors.length+"個構造方法"); //獲得構造方法的引數數量和型別 for (Constructor constructor : constructors) { //獲取引數數量 int count=constructor.getParameterCount(); System.out.println("該構造方法有"+count+"個引數"); //獲取引數型別 Class[] classes=constructor.getParameterTypes(); for (Class aClass : classes) { System.out.println(aClass.getName()+"\t"); } } //使用無參構造 Constructor con1=((Class) objClass).getConstructor(); Object Obj1=con1.newInstance(); System.out.println("無參構造例項化物件是:"+Obj1); //帶有String的構造 Constructor con2=((Class) objClass).getConstructor(String.class); Object Obj2=con2.newInstance("我是一個標題"); System.out.println("帶參構造例項化物件是:"+Obj2);
若是想要獲得父類和子類所以的屬性,則需要進行遞迴,先對子類進行屬性的獲得,然後獲得子類的父類,如果不是Object型別,則使用遞迴將父類傳入繼續進行屬性的獲得
XML的使用:
根標籤:(user是標籤名稱, id是標籤屬性, 1001是標籤值, userName和password是標籤體的內容)
XML中每個標籤都稱為節點或元素,標籤體的文字也是節點元素,稱為文字節點
(紫色標記的都是節點,紅色標記的都是文字加點,所以一共11個節點)
框架中靈活處理的內容都要寫成配置檔案,通過底層程式碼對配置檔案進行解析,解析完成後通過反射進行處理呼叫
<?xml version="1.0" encoding="UTF-8"?>
//相當於集合儲存使用者資訊 <users> //使用者一 <user id="1001" age=20> //標籤體(標籤內容) <userName>tom</userName> <password>tom123</password> </user> //標籤二:使用者二 <user id="1002" age=21> //標籤體(標籤內容) <userName>jack</userName> <password>jack123</password> </user> </users>
package com.igeek; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import java.util.List; /** * 使用DOM4J對XML文件進行解析 */ public class Demo3 { public static void main(String[] args) { //使用ClassLoader獲取資源是在類路徑(src資料夾內)中訪問的 //System.out.println(Demo3.class.getClassLoader().getResource("").getPath()); //使用類自身Class物件獲取資源是在類所在的包路徑中訪問的 //System.out.println(Demo3.class.getResource("").getPath()); //從類路徑中訪問檔案並將檔案轉換為輸入流 //System.out.println(Demo3.class.getClassLoader().getResourceAsStream("test.xml")); try { //建立SAX解析器物件 SAXReader reader = new SAXReader(); //通過獲取xml檔案的輸入流,載入文件
//通過類的class獲取classLoader ,在通過classLoader讀取檔案的輸入流
//這個方式是從當前類所在的包中查詢test.xml檔案
//Document document=reader.read(Dome3.class.getClass().getResourceAsStream("test.xml"));
//這個方式是從整個專案的路徑中查詢test.xml檔案 Document document = reader.read(Demo3.class.getClassLoader().getResourceAsStream("test.xml")); //獲取文件的根節點物件 Element root = document.getRootElement(); //訪問節點的名字 System.out.println(root.getName()); //訪問節點中的所有下一層子節點 List<Element> list = root.elements();//獲取的是陣列:所有的節點 //遍歷user標籤 for (Element element : list) { System.out.println(element.getName()); //訪問標籤的所有屬性,也可以通過attribute通過名稱獲取單獨的一個屬性 List<Attribute> attributeList = element.attributes();//得到的是集合所有的屬性 //遍歷屬性(屬性的型別是:Attibute標籤的型別是:Element) for (Attribute attribute : attributeList) { //獲取屬性的名稱 System.out.print("\t"+attribute.getName()+":"); //獲取屬性的值 System.out.println(" "+attribute.getValue()); } //獲得指定的userName子標籤 Element nameNode = element.element("userName"); System.out.println("\t"+nameNode.getName()); //獲取userName的標籤體文字:trim是去除空格(如果只是需要查詢不需要操作,也可以不用接收直接列印) String name = nameNode.getTextTrim(); System.out.println("\t\t"+name); //獲取password子標籤 Element pwdNode = element.element("password"); System.out.println("\t"+pwdNode.getName()); System.out.println("\t\t"+pwdNode.getTextTrim()); } } catch (DocumentException e) { e.printStackTrace(); } } }