首頁 > 科技

終於有大神把Java反射詳解的明明白白了,網友:小白還不快收藏

2021-06-25 15:30:06

Hello,今天給各位童鞋們分享的是Java反射,趕緊拿出小本子記下來吧

反射概述

什麼是反射

將類的各個組成部分封裝為其他物件的過程就叫做 反射,其中 組成部分指的是我們類的 成員變數(Field)構造方法(Constructor)成員方法(Method)

使用反射的優缺點

優點在程式運行過程中可以操作類物件,增加了程式的靈活性;解耦,從而提高程式的可擴展性,提高程式碼的複用率,方便外部呼叫;對於任何一個類,當知道它的類名後,就能夠知道這個類的所有屬性和方法;而對於任何一個物件,都能夠呼叫它的一個任意方法。缺點效能問題:Java 反射中包含了一些動態類型,JVM 無法對這些動態程式碼進行優化,因此通過反射來操作的方式要比正常操作效率更低。安全問題:使用反射時要求程式必須在一個沒有安全限制的環境中運行,如果程式有安全限制,就不能使用反射。程式健壯性:反射允許程式碼執行一些平常不被允許的操作,破壞了程式結構的抽象性,導致平臺發生變化時抽象的邏輯結構無法被識別。Class 物件的獲取及使用

獲取 Class 物件的方式

Class.forName("全類名")原始碼階段,它能將位元組碼檔案載入進記憶體中,然後返回 Class 物件,多用於 配置檔案 中,將類名定義在配置檔案中,通過讀取配置檔案來載入類。

2.類名.class

類物件階段,通過類名的 class 屬性來獲取,多用於 參數的傳遞

3.物件.getClass()

運行時階段,getClass() 定義在 Object 類中,表明所有類都能使用該方法,多用於 物件的獲取位元組碼的方式。

我們首先定義一個 Person 類,用於後續反射功能的測試;

定義好 Person 類之後,我們嘗試用 3 種不同的方式來獲取 Class 物件,並比較它們是否相同。

上述程式碼中,會發現最後輸出的比較結果返回的是兩個 true,說明通過上述三種方式獲取的 Class 物件都是同一個,同一個位元組碼檔案(*.class)在一次運行過程中只會被載入一次

Class 物件的使用

獲取成員變數

Field[] getFields()

回顧下我們的 Person 類,可以發現 id、grade 成員變數都是被 public 所修飾的,說明該方法是用於獲取類中所有被 public 所修飾的成員變數(包括父類)。

Field getField(String name)

從上面的結果分析可知,該方法只能用於獲取類中指定名稱的 public 所修飾的成員變數,對於 protected、private 所修飾的成員變數,該方法是無法獲取的(包括父類)。而獲取或設定成員變數值時,可以通過 get/set 方法來操作,具體操作方法如下。

Field[] getDeclaredFields()

觀察上面的結果可知,該方法可用於獲取所有的成員變數,不用考慮修飾符的限制(不包括父類)。

Field getDeclaredField(String name)

觀察上面的結果可知,該方法可用於獲取指定的成員變數,不用考慮成員變數修飾符的限制(不包括父類)。但是在利用 set、get 方法來獲取和設定 private、protected 修飾的成員變數時,需要利用 setAccessible() 來忽略訪問全新啊修飾符的安全檢查,否則程式將會報錯。

獲取構造方法

Constructor<?>[] getConstructors()類似於通過 Class 例項來獲取成員變數,該方法用於獲取所有 public 所修飾的構造方法(包括父類);Constructor<T> getConstructor(類<?>... parameterTypes)該方法用於獲取某一指定參數類型後的 public 所修飾的構造方法(包括父類);

Constructor<?>[] getDeclaredConstructors()該方法用於獲取所有 public 所修飾的構造方法(不包括父類);

Constructor<T> getDeclaredConstructor(類<?>... parameterTypes)該方法用於獲取某一指定參數類型後的 public 所修飾的構造方法(不包括父類);

而獲取到構造方法之後,我們就可以利用 newInstance() 方法來創建類的例項。特殊的,如果我們的構造方法是無參的,此時則可以直接利用 Class.newInstance() 來構造例項。

獲取成員方法

Method[] getMethods()用於獲取當前類的所有 public 所修飾的成員方法(包括父類)。

Method getMethod(String name, 類<?>... parameterTypes)用於獲取當前類的某一個指定名稱 public 所修飾的成員方法(包括父類)。

Method[] getDeclaredMethods()用於獲取當前類的所有 public 所修飾的成員方法(不包括父類)。

Method getDeclaredMethods(String name, 類<?>... parameterTypes)用於獲取當前類的某一個指定名稱 public 所修飾的成員方法(不包括父類)。

而當我們獲取到類的成員方法後,如果要執行某一個方法,可以使用 invoke() 方法來執行該方法。

獲取類名

String getName()從上述程式的結果可知,當我們獲取到 Class 物件之後,如果不知道類的全名,就可以使用 getName() 來獲取該類的全名。

反射例項

假設我們有如下需求:在不改變類的程式碼的前提下,我們能夠創建任意類的物件,並執行其中的方法。

此時,我們可以通過 配置檔案 + 反射的方式來實現這一效果,而這也就是我們現在所用框架中的基礎,當我們使用反射後,只需要通過修改配置檔案中的內容就能夠不用去改程式碼就實現對應的功能。

假設我們有兩個類,一個 Student,一個 Teacher,兩者的定義如下;

要實現我們的需求,通常需要如下步驟:

將要創建物件的全類名和要執行的方法都配置在配置檔案中;定義的配置檔案 prop.properties ,其中主要內容包括 className 和 methodName 兩個屬性,分別代表類的全類名和要呼叫方法的名字。一個具體例項如下,分別代表名為 Student 的類和名為 study 的方法。

2.然後在主方法中載入讀取配置檔案;

3.利用反射技術將類載入到記憶體中;

4.接著利用 newInstance() 方法創建物件;

5.最後則是利用 invoke() 方法來執行方法;

將整個流程彙總起來就是:

此時,我們只需要改動配置檔案 prop.properties 中的配置即可輸出不同結果;

好啦,今天的文章就到這裡了,希望能夠幫助到螢幕前迷茫的你們

如何獲取Java學習資料?

轉發分享此文,後臺私信小編:「 資料 」即可獲取。注意是私信,因為檔案比較大,所以要加好友,免費,不花錢(注:轉發分享,感謝大家


IT145.com E-mail:sddin#qq.com