1. 程式人生 > >Java基礎加強-反射機制

Java基礎加強-反射機制

對象 int 個數 包裝類 [] 包裝 地址 for hashset

反射的基石 -> Class 類(字節碼)
/*只要是在源程序中出現的類型,都要各自的Class實例對象,例如:int,int[],void*/
如何得到各個字節碼對應的實例對象(Class類型)
1.類名.class
2.對象.getClass
3.Class.forName("類名");(1.先忘內存中找,是否有這個字節碼 有的話,就是用,沒有的話 就使用類裝載器的方式,得到字節碼)
/*這三種方式得到的字節碼 都是同一份 是一樣的*/
九個預定義Class實例對象(八種基本數據類型 + void )
1.Class.isPrimitive 判斷是否為預定義的實例對象
2.int.class == Integer.TYPE (Integer.TYPE 得到該被包裝類型的字節碼)
3.int.class != Integer.class (這是兩種不同的類型,字節碼也不同)

反射
/*反射就是把Java類中的各種成分(成員變量,方法,構造方法,包等)映射成相應的java類。*/
1.得到某個類的構造方法 Constructor
Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class)
Class.newInstance()方法 調用默認無參構造方法創建對象(用到了緩存機制來保存默認構造方法的實例對象)

2.成員變量的反射 Field
Field name = Class.forName("xxx.xxx.Person").getField("name"); //name不是某個對象(person)上的變量,而是某個類(Person)上的,要用它去取某個對象上對應的值
field.get(person);//需指定是哪個對象的成員變量

3.成員方法的反射 Method
String str1 = "abc"
Mehod methodCharAt = String.class.getMethod("charAt",int.class); //得到某個類的成員方法
System.out.println(methodCharAt.invoke(str1,1)); /*結果:b*/ //調用哪個對象的該方法,傳遞什麽參數
如果invoke第一個參數傳遞為 null ,說明調用該類的一個靜態方法

/*
* 人在黑板上畫圓,涉及三個對象,畫圓需要圓心和半徑,但是是私有的,畫圓的方法
* 分配給人不合適。
*
* 司機踩剎車,司機只是給列車發出指令,剎車的動作還需要列車去完成。
*
* 面試經常考面向對象的設計,比如人關門,人只是去推門。
*
* 這就是專家模式:誰擁有數據(private),誰就是專家,方法就分配給誰
*/

4.用反射方法執行某個類中的main方法
main方法所需的參數是一個字符串數組,當反射調用這個main方法時,invoke傳遞參數時不能直接給一個字符串數組參數,因為編譯的時候會將該字符串數組拆開,變成多個參數,
而main方法只要一個參數,故報錯 解決辦法:將傳遞的字符串數組封裝成一個Object對象 或者 一個Object[] 對象

5.數組的反射
具有相同維數和元素類型的數組屬於同一個類型,即具有相同的Class實例對象
1.所有的數組
int[][]a1 = new int[3][3];
Object[] o1 = a1; /*正確的,int[] 屬於Object*/
2.八大基本數據類型不繼承於Object
int[] a2 = new int[3];
Object[] o2 = a2; /*錯誤的,int不屬於Object*/

註:Arrays.asList()方法,在jdk 1.4 中,由於 /*沒有可變參數*/,接收的參數時Object[] ,在jdk 5.0 中 接收的參數是一個可變參數
故,當System.out.println(Arrays.asList(String[])); 會打印出String數組中的元素的值 因為這裏是 /*jdk1.4 去編譯*/,
當System.out.println(Arrays.asList(int[])); 因為 /*int不屬於Object*/,所以 /*jdk1.4 無法編譯 而是5.0 去編譯(只會解析一個參數)*/,此時無法打印出元素,而是打印對象

6.ArrayList(有序可重復)和HashSet(無序不可重復)
存數據到ArrayList中時,一個對象一個空間,即使如果這兩個數據相互equals,同樣是按順序放到ArrayList中
而HashSet,是一整塊混亂的空間,如果存數據時,兩個數據equals,後面的那個數據不會存進去

Set集合想要保證元素不重復,可兩個元素是否重復應該依據什麽來判斷呢?( /*先調用新元素HashCode方法,得到物理位置,如果該位置沒有元素,那新元素就放到這裏,如果有,再equals*/)
這就是Object.equals方法了。但是,如果每增加一個元素就檢查一次,那麽當元素很多時,後添加到集合中的元素比較的次數就非常多了。
初學者可以這樣理解,hashCode方法實際上返回的就是對象存儲的物理地址(實際可能並不是)。
當集合要添加新的元素時, /*先調用這個元素的hashCode方法*/,就一下子能定位到它應該放置的物理位置上。
如果這個位置上沒有元素,它就可以直接存儲在這個位置上,不用再進行任何比較了;如果這個位置上已經有元素了,就調用它的equals方法與新元素進行比較,相同的話就不存了,不相同就散列其它的地址

註:java中的內存泄漏,比如某些東西用不到了,想從內存中移除它,釋放內存,
當一個對象被存儲進HashSet集合中以後,就不能修改這個對象中那些參與計算哈希值的字段了,否則, /*對象修改後的哈希值與最初存儲進HashSet集合中時的哈希值就不同了*/,
導致無法從HashSet集合中單獨刪除當前對象,從而造成 /*內存泄漏*/

7.反射的作用->實現框架功能
框架要解決的核心問題,我在框架時,你這個用戶可能還在上小學 還不會寫程序,我寫的框架程序怎樣才能調用到你以後寫的類呢,(不知道會寫出什麽類)
因為在寫程序時,無法知道直接知道要被調用的類名,所以,在程序中,無法直接new某個類的實例對象,而要用到反射來做 (也需要讀取配置文件)

Java基礎加強-反射機制