反射基礎 在應用反射機制之前,首先我們先來看一下如何獲取一個對象對應的反射類Class,在Java中我們有三種方法可以獲取一個對象的反射類。 通過getClass方法 在Java中,每一個Object都有一個getClass()方法,通過getClass方法我們可以獲取到這個對象對應的反射類: 1 ...
反射基礎
在應用反射機制之前,首先我們先來看一下如何獲取一個對象對應的反射類Class
,在Java中我們有三種方法可以獲取一個對象的反射類。
通過getClass方法
在Java中,每一個Object
都有一個getClass()
方法,通過getClass方法我們可以獲取到這個對象對應的反射類:
1 2 |
|
通過forName方法
我們也可以調用Class
類的靜態方法forName()
:
1 |
|
使用.class
或者我們也可以直接使用.class
:
1 |
|
獲取類型信息
在文章開頭我們就提到反射的一大好處就是可以允許我們在運行期間獲取對象的類型信息,下麵我們通過一個例子來具體看一下。
首先我們在typeinfo.interfacea
包下麵新建一個介面A
:
1 2 |
|
接著我們在typeinfo.packageaccess
包下麵新建一個介面C
,介面C
繼承自介面A
,並且我們還另外創建了幾個用於測試的方法,註意下麵幾個方法的許可權都是不同的。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
在callHiddenMethod()
方法中我們用到了幾個新的API,其中getDeclaredMethod()
根據方法名用於獲取Class類指代對象自己聲明的某個方法,然後我們通過調用invoke()
方法就可以觸發對象的相關方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
從輸出結果我們可以看出來,不管是public
,default
,protect
還是pricate
方法,通過反射類我們都可以自由調用。當然這裡我們只是為了顯示反射的強大威力,在實際開發中這種技巧還是不提倡。
1 2 3 4 5 6 |
|
上面我們只是測試了Method
對象,感興趣的讀者在熟悉了反射的API之後,不妨測試一下Filed
,這裡我們就不重覆了。
與註解相結合
在單元測試框架比如Junit
中反射機制也得到了廣泛的應用,即通過註解的方式。下麵我們簡單地來瞭解一下如何通過反射機制來獲取相關方法的註解信息,比如說我們有下麵這樣一個業務場景,當用戶在修改自己密碼的時候,為了保證密碼的安全性,我們要求用戶的新密碼要滿足一些條件,比如說至少要包含一個非數字字元,不能與以前的密碼相同之類的條件等。
1 2 3 4 5 6 7 |
|
下麵是我們檢測密碼的工具類的實現:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
利用反射我們可以寫出更加清晰的測試代碼,其中getDeclaredMethods()
方法可以獲取相關對象自己聲明的相關方法,而getAnnotation()
則可以獲取Method
對象的指定註解。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
解決泛型擦除
現在有下麵這樣一個業務場景,我們有一個泛型集合類List<Class<? extends Pet>>
,我們需要統計出這個集合類中每種具體的Pet
有多少個。由於Java的泛型擦除,註意類似List<? extends Pet>
的做法肯定是不行的,因為編譯器做了靜態類型檢查之後,到了運行期間JVM會將集合中的對象都視為Pet
,但是並不會知道Pet
代表的究竟是Cat
還是Dog
,所以到了運行期間對象的類型信息其實全部丟失了。
為了實現我們上面的例子,我們先來定義幾個類:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
上面的Pet
類繼承自Individual
,Individual
類的的實現稍微複雜一點,我們實現了Comparable
介面,重新自定義了類的比較規則,如果不是很明白的話,也沒有關係,我們已經將它抽象出來了,所以不理解實現原理也沒有關係。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
|
下麵創建了一個抽象類PetCreator
,以後我們通過調用arrayList()
方法便可以直接獲取相關Pet
類的集合。這裡使用到了我們上面沒有提及的newInstance()
方法,它會返回Class類所真正指代的類的實例,這是什麼意思呢?比如說聲明new Dog().getClass().newInstance()
和直接new Dog()
是等價的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
接下來我們來實現上面這一個抽象類,解釋一下下麵的代碼,在下麵的代碼中,我們聲明瞭兩個集合類,allTypes
和types
,其中allTypes
中包含了我們呢上面所聲明的所有類,但是我們具體的類型實際上只有兩種即Mutt
和EgypianMau
,所以我們真正需要new
出來的寵物只是types
中所包含的類型,以後我們通過調用getTypes()
便可以得到types
中所包含的所有類型。
1 2 3 4 5 6 7 8 9 10 |
|
總體的邏輯已經完成了,最後我們實現用來統計集合中相關Pet
類個數的TypeCounter
類。解釋一下isAssignalbeFrom()
方法,它可以判斷一個反射類是某個反射類的子類或者間接子類。而getSuperclass()
顧名思義就是得到某個反射類的父類了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
喜歡的朋友可以點贊關註,一起學習進步