這篇文章主要為大家詳細介紹了Java方法反射的實現原理,具有一定的參考價值,有興趣的小夥伴們可以參考一下
部落客說: Java 反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意方法和屬性;這種動態獲取資訊以及動態調用對象方法的函數稱為Java 語言的反射機制。在本文中,佔小狼分析了 Java 反射機制的實作原理(原始碼),有興趣的同學可以透過閱讀本文花上幾分鐘了解了解。
正文
方法反射實例
public class ReflectCase { public static void main(String[] args) throws Exception { Proxy target = new Proxy(); Method method = Proxy.class.Java反射實作方法的原理詳解("run"); method.Java反射實作方法的原理詳解(target); } static class Proxy { public void run() { System.out.println("run"); } } }
透過Java 的反射機制,可以在運行期間調用物件的任何方法,如果大量使用這種方式進行調用,會有效能或記憶體隱患麼?為了徹底了解方法的反射機制,只能從底層程式碼入手啦!
Method 取得
呼叫 Class 類別的Java反射實作方法的原理詳解可以取得指定方法名稱和參數的方法物件 Method。
Java反射實作方法的原理詳解
#其中Java反射實作方法的原理詳解方法從快取或Java反射實作方法的原理詳解 中取得該Class 中申明的方法列表,Java反射實作方法的原理詳解方法將從返回的方法清單裡找到一個符合名稱和參數的方法物件。
Java反射實作方法的原理詳解
如果找到一個符合的Method,則重新複製一份返回,即Method.copy( )
方法。
所次每次呼叫Java反射實作方法的原理詳解方法回傳的Method 物件其實都是一個新的對象,且新物件的root屬性都指向原來的Method 對象,如果需要頻繁調用,最好把Method 物件緩存起來。
Java反射實作方法的原理詳解
從快取或Java反射實作方法的原理詳解 取得該Class 中申明的方法列表,實作如下:
#其中Java反射實作方法的原理詳解()方法實作如下:
這裡有個比較重要的資料結構ReflectionData,用來快取從Java反射實作方法的原理詳解 讀取類別的如下屬性資料:
從Java反射實作方法的原理詳解()方法實作可以看出:Java反射實作方法的原理詳解物件是SoftReference類型的,說明在記憶體緊張時可能會被回收,不過也可以透過-XX:SoftRefLRUPolicyMSPerMB參數控制回收的時機,只要發生GC就會將其回收,如果Java反射實作方法的原理詳解被回收之後,又執行了反射方法,那隻能透過Java反射實作方法的原理詳解方法重新建立一個這樣的物件了,Java反射實作方法的原理詳解方法實作如下:
透過unsafe.compareAndSwapObject方法重新設定Java反射實作方法的原理詳解欄位;在Java反射實作方法的原理詳解方法中,如果透過Java反射實作方法的原理詳解()取得的ReflectionData物件不為空,則嘗試從ReflectionData物件中取得declaredMethods屬性,如果是第一個物件不為空,則嘗試從ReflectionData物件中取得declaredMethods屬性,如果是第一個物件不為空,則嘗試從ReflectionData物件中取得declaredMethods屬性,如果是第物件一次,或則被GC回收之後,重新初始化後的類別屬性為空,則需要重新到Java反射實作方法的原理詳解 中取得一次,並賦值給ReflectionData,下次呼叫就可以使用快取資料了。
Method 呼叫
取得到指定的方法物件Method 之後,就可以呼叫它的Java反射實作方法的原理詳解方法了,Java反射實作方法的原理詳解實作如下:
應該注意到:這裡的Java反射實作方法的原理詳解物件是Java反射實作方法的原理詳解方法實現的關鍵,一開始methodAccessor為空,需要呼叫acquireJava反射實作方法的原理詳解產生一個新的Java反射實作方法的原理詳解對象,Java反射實作方法的原理詳解本身就是一個接口,實作如下:
在acquireJava反射實作方法的原理詳解方法中,會透過ReflectionFactory類別的newJava反射實作方法的原理詳解建立一個實作了Java反射實作方法的原理詳解介面的對象,實作如下:
在ReflectionFactory類別中,有2 個重要的欄位:noInflation(預設false)和inflationThreshold(預設為15),在checkInitted方法中可以透過-Dsun.reflect.inflationThreshold=xxx和-Dsun.reflect.noInflation=true對這兩個欄位重新設置,而且只會設定一次;如果noInflation為false,方法newJava反射實作方法的原理詳解都會傳回DelegatingJava反射實作方法的原理詳解Impl對象,DelegatingJava反射實作方法的原理詳解Impl的類別實作:
其實,DelegatingJava反射實作方法的原理詳解Impl物件物件就是一個代理對象,負責呼叫被代理對象delegate的Java反射實作方法的原理詳解方法,其中delegate參數目前是NativeJava反射實作方法的原理詳解Impl對象,所以最終Method 的Java反射實作方法的原理詳解方法調用的是NativeJava反射實作方法的原理詳解Impl對象Java反射實作方法的原理詳解方法,實現如下:
################################################################## #####這裡用到了ReflectionFactory類別中的inflationThreshold,當delegate呼叫了15次Java反射實作方法的原理詳解方法之後,如果繼續呼叫就透過Java反射實作方法的原理詳解Generator類別的generateMethod方法產生Java反射實作方法的原理詳解Impl對象,並設定為delegate對象,這樣下次執行Method. Java反射實作方法的原理詳解時,就呼叫新建的Java反射實作方法的原理詳解物件的Java反射實作方法的原理詳解()方法了。這裡要注意的是:generateMethod方法在產生Java反射實作方法的原理詳解Impl物件時,會在記憶體中產生對應的字節碼,並呼叫ClassDefiner.defineClass建立對應的Class 對象,實作如下:############ ####在ClassDefiner.defineClass方法實作中,每被呼叫一次都會產生一個Java反射實作方法的原理詳解類別載入器物件:###############這裡每次都會產生新的類別載入器,是為了性能考慮,在某些情況下可以卸載這些生成的類,因為類的卸載是只有在類加載器可以被回收的情況下才會被回收的,如果用了原來的類加載器,那可能導致這些新創建的類別一直無法被卸載,從其設計來看本身就不希望這些類別一直存在內存裡的,在需要的時候有就行啦! ###以上是Java反射實作方法的原理詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!