反射(一)-常用方法及載入資源文件
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類讀取記憶體中的配置資訊;