1、初識反射
1.1什么是反射
? 反射是指在程式運行期間,能夠觀察和修改類或者類的物件的屬性和行為的特性;
1.2 編譯時與運行時
編譯時
? 編譯時顧名思義就是正在編譯的時候 . 那啥叫編譯呢?就是編譯器幫你把源代碼翻譯成機器能識別的代碼 ;
? 編譯時就是簡單的作一些翻譯作業 ,比如檢查老兄你有沒有粗心寫錯啥關鍵字了啊.有啥詞法分析,語法分析之類的程序. 就像個老師檢查學生的作文中有沒有錯別字和病句一樣;
運行時
所謂運行時就是代碼跑起來了.被裝載到記憶體中去了;
(你的代碼保存在磁盤上沒裝入記憶體之前是個死家伙.只有跑到記憶體中才變成活的);
2、反射獲取Class物件的四種方法
| getClass() | 適合有物件實體的情況下 |
|---|---|
| .class | 僅適合在編譯前就已經明確要操作的 Class |
| forName(“類的全類名”) | 已明確類的全路徑名 |
| loadClass(“類的全類名”); | 通過類加載器的loadClass(類的全路徑名) |
2.1 getClass()
Person person = new Person();
//第一種:getClass() 需要有物件實體
Class<Person> class1 = (Class<Person>)person.getClass();
System.out.println("==物件.getClass()==:"+class1); //com.kgc.reflection.Person
2.2 .class
//第二種:.class 需要明確操作的Class
Class<Person> class1_2 = Person.class;
System.out.println("==類.class==:"+class1_2);//com.kgc.reflection.Person
2.3 forName()
//第三種:forName() 需要類的全路徑名
Class<Person> class1_3 = (Class<Person>)Class.forName("kgc.reflection.TestPerson");
System.out.println("==Class.forName(‘類路徑’)==:"+class1_3);//com.kgc.reflection.Person
2.4 loadClass(“類的全類名”);
//4.通過類加載器的loadClass("類的全類名");
ClassLoader classLoader = this.getClass().getClassLoader();
Class<Person> class1_4 = (Class<Person>)classLoader.loadClass("com.kgc.reflection.Person");
System.out.println("通過類加載器的loadClass"+class1_4.getName());//com.kgc.reflection.Person
3、通過Class類初始化物件
3.1 無參構造方法
//先獲得Class物件java
Class<Person> class2 = Person.class;
//創建實體物件,呼叫默認的空參構造
Person person2 = class2.newInstance();
System.out.println(person2); //Person{name='null', age=null}
3.2 有參構造方法
//先獲得Class物件java
Class<Person> class2 = Person.class;
//通過Class物件獲取有參構造類物件
Constructor<Person> constructor = class2.getConstructor(String.class, Integer.class);
//通過有參構造類物件的newInstance方法初始化物件
Person person3 = constructor.newInstance("化羽", 12);
System.out.println(person3); //Person{name='張三', age=30}
4、獲取并修改屬性值
4.1 對getDeclared...的理解
| getField,Mothed,Constructor | 獲取自己及父類的屬性,方法,構造器(不包括私有的) |
|---|---|
| getDeclaredField,Mothed,Constructor | 只獲取自己類的屬性,方法,構造器(包括私有的) |
4.2 非私有屬性
| getField(String name) | 獲取非私有屬性 |
|---|---|
| set(物件實體, Object value) | 對指定實體的指定屬性賦值 |
//name的定義:public String name;
//獲取 非私有屬性 name
Field fieldName = class2.getField("name");
//通過 屬性實體名.set(物件實體,屬性值) 對指定實體的指定屬性賦值
fieldName.set(person3,"張三");
System.out.println(person3); //Person{name='張三', age=12} //name發生了該改變
4.3 私有屬性
| getDeclaredField(String name) | 獲取私有屬性及其他屬性 |
|---|---|
| setAccessible(boolean flag) | 是否取消 Java 語言訪問檢查(true是,false否) |
| set(物件實體, Object value) | 對指定實體的指定屬性賦值 |
//通過反射,獲取運行時類的屬性,private age,無法使用getField,必須是使用getDeclaredField,設定訪問權限
//age的定義:private Integer age;
//獲得 私有屬性age
Field fieldAge = class2.getDeclaredField("age");
//取消 Java 語言訪問檢查
fieldAge.setAccessible(true);
//通過 屬性實體名.set(物件實體,屬性值) 對指定實體的指定屬性賦值
fieldAge.set(person3,30);
System.out.println(person3); //Person{name='張三', age=30} //age發生了變化
5、獲取并使用方法
5.1 無參方法
| getMethod(方法名) | 獲取無參方法 |
|---|---|
| invoke(物件實體) | 執行無參方法 |
//sayHi()方法:System.out.println("我是一個人,我的名字叫:"+name+",今年:"+age+"歲");
Method methodHi = class2.getMethod("sayHi");
methodHi.invoke(person3); //我是一個人,我的名字叫:張三,今年:30歲
5.2 有參方法
| getMethod(方法名,引數類) | 獲取有參方法 |
|---|---|
| invoke(物件實體,引數) | 執行有參方法 |
//sayHello(String nation)方法: System.out.println("我的國際是:"+nation);
Method methodHello = class2.getMethod("sayHello", String.class);
methodHello.invoke(person3,"中國"); //我的國際是:中國
5.3 私有方法
| getDeclaredMethod(方法名,引數類) | 獲取私有方法及其他方法 |
|---|---|
| setAccessible(boolean flag) | 是否取消 Java 語言訪問檢查(true是,false否) |
| invoke(實體,引數) | 執行有參私有方法 |
//private void myMoney(double money){
// System.out.println("我有"+money+"私房錢!");
// }
//呼叫私有方法
//getDeclaredMethod("myMoney", double.class) 獲取方法
Method myMoney = class2.getDeclaredMethod("myMoney", double.class);
//取消Java語言訪問檢查
myMoney.setAccessible(true);
//執行方法
myMoney.invoke(person3,2.5); //我有2.5私房錢!
6、類加載器
6.1 三種類加載器
| BootStrap ClassLoader | 引導類加載器(Java的核心庫,都是通過此加載器加載到記憶體的) |
|---|---|
| Extension ClassLoader | 擴展類加載器 |
| System ClassLoader | 系統類加載器(所有的自定義加載列,都是系統類加載器) |
//1.系統類加載器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader); //sun.misc.Launcher$AppClassLoader@18b4aac2
//2.擴展類加載器:系統類加載器的父類
ClassLoader ExtClassLoader = systemClassLoader.getParent();
System.out.println(ExtClassLoader);//sun.misc.Launcher$ExtClassLoader@8efb846
//3引導類加載器擴展類加載器的引導類,無法直接獲取;(Java的核心庫,都是通過此加載器加載到記憶體的)
ClassLoader bootstapLoader = ExtClassLoader.getParent();
System.out.println(bootstapLoader); //null
//4.所有的自定義加載列,都是系統類加載器
ClassLoader classLoader4 = Person.class.getClassLoader();
System.out.println(classLoader4); //sun.misc.Launcher$AppClassLoader@18b4aac2
//5.Sting類的默認類加載器 ,引導類加載器(Java的核心庫,都是通過此加載器加載到記憶體的)
ClassLoader classLoader5 = String.class.getClassLoader();
System.out.println(classLoader5); //null
幾種類加載器的關系

雙親委派機制
Java虛擬機對class檔案采用的是按需加載,加載類的class檔案時使用的時雙親委派模式,即把請求交給父類處理,如果父類加載器還有父類,則進一步向上委托,直到啟動類加載器,如果父類加載器加載成功,則回傳,否則其子類加載器才會嘗試加載,他是一種任務委派模式;
6.2 通過類加載器讀取組態檔
jdbc.properties中的資訊
#key=value
user_name=kh96
usre_pwd=123123
6.2.1 使用位元組流將組態檔加載到記憶體中
//創建一個properties類物件
Properties properties = new Properties();
//創建一個位元組輸入流
//注意: 使用輸入流來讀取檔案時默認在當前專案下查找
FileInputStream fileInputStream = new FileInputStream("src/jdbc.properties");
//呼叫properties的load()方法來讀取加載到記憶體中的組態檔
properties.load(fileInputStream);
//獲取組態檔中的資訊
Object user_name = properties.get("user_name");
Object usre_pwd = properties.get("usre_pwd");
System.out.println("資料庫的用戶名:"+user_name); //kh96
System.out.println("資料庫的密碼:"+usre_pwd); //123123
6.2.2 使用ClassLoader(類加載器(具體是:系統類加載器))將組態檔加載到記憶體中來
//創建一個properties類物件
Properties properties = new Properties();
//通過當前類獲取類加載器(系統類加載器)
ClassLoader classLoader = this.getClass().getClassLoader();
System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2
//通過系統類加載器物件呼叫getResourceAsStream()方法以流的形式獲取資源,將組態檔加載到記憶體中
//注意: 我們使用類加載器的getResourceAsStream(String path)方法來獲取資源時默認是在本專案的src檔案目錄之下獲取
classLoader.getResourceAsStream("jdbc.properties");
//獲取組態檔中的資訊
Object user_name = properties.get("user_name");
Object usre_pwd = properties.get("usre_pwd");
System.out.println("資料庫的用戶名:"+user_name); //kh96
System.out.println("資料庫的密碼:"+usre_pwd); // 123123
總結
都是先將組態檔以流的形式加載到記憶體,再通過Properties類讀取記憶體中的配置資訊;
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/495522.html
標籤:其他
上一篇:這將使你見過最全面的Python制作GUI學生管理系統教程
下一篇:java繼承簡介說明
