日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

深入分析 Java 方法反射的实现原理

發布時間:2024/4/13 java 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入分析 Java 方法反射的实现原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

方法反射實例


??? public class ReflectCase {


??????? public static void main(String[] args) throws Exception {

??????????? Proxy target = new Proxy();

??????????? Method method = Proxy.class.getDeclaredMethod("run");

??????????? method.invoke(target);

??????? }


??????? static class Proxy {

??????????? public void run() {

??????????????? System.out.println("run");

??????????? }

??????? }

??? }


通過Java的反射機制,可以在運行期間調用對象的任何方法,如果大量使用這種方式進行調用,會有性能或內存隱患么?為了徹底了解方法的反射機制,只能從底層代碼入手了。


Method獲取


調用Class類的getDeclaredMethod可以獲取指定方法名和參數的方法對象Method。


getDeclaredMethod

其中privateGetDeclaredMethods方法從緩存或JVM中獲取該Class中申明的方法列表,searchMethods方法將從返回的方法列表里找到一個匹配名稱和參數的方法對象。


searchMethods

如果找到一個匹配的Method,則重新copy一份返回,即Method.copy()方法

所次每次調用getDeclaredMethod方法返回的Method對象其實都是一個新的對象,且新對象的root屬性都指向原來的Method對象,如果需要頻繁調用,最好把Method對象緩存起來。


privateGetDeclaredMethods


從緩存或JVM中獲取該Class中申明的方法列表,實現如下:

其中reflectionData()方法實現如下:

這里有個比較重要的數據結構ReflectionData,用來緩存從JVM中讀取類的如下屬性數據:

從reflectionData()方法實現可以看出:reflectionData對象是SoftReference類型的,說明在內存緊張時可能會被回收,不過也可以通過-XX:SoftRefLRUPolicyMSPerMB參數控制回收的時機,只要發生GC就會將其回收,如果reflectionData被回收之后,又執行了反射方法,那只能通過newReflectionData方法重新創建一個這樣的對象了,newReflectionData方法實現如下:

通過unsafe.compareAndSwapObject方法重新設置reflectionData字段;


在privateGetDeclaredMethods方法中,如果通過reflectionData()獲得的ReflectionData對象不為空,則嘗試從ReflectionData對象中獲取declaredMethods屬性,如果是第一次,或則被GC回收之后,重新初始化后的類屬性為空,則需要重新到JVM中獲取一次,并賦值給ReflectionData,下次調用就可以使用緩存數據了。


Method調用


獲取到指定的方法對象Method之后,就可以調用它的invoke方法了,invoke實現如下:

應該注意到:這里的MethodAccessor對象是invoke方法實現的關鍵,一開始methodAccessor為空,需要調用acquireMethodAccessor生成一個新的MethodAccessor對象,MethodAccessor本身就是一個接口,實現如下:

在acquireMethodAccessor方法中,會通過ReflectionFactory類的newMethodAccessor創建一個實現了MethodAccessor接口的對象,實現如下:

在ReflectionFactory類中,有2個重要的字段:noInflation(默認false)和inflationThreshold(默認15),在checkInitted方法中可以通過-Dsun.reflect.inflationThreshold=xxx和-Dsun.reflect.noInflation=true對這兩個字段重新設置,而且只會設置一次;


如果noInflation為false,方法newMethodAccessor都會返回DelegatingMethodAccessorImpl對象,DelegatingMethodAccessorImpl的類實現

其實,DelegatingMethodAccessorImpl對象就是一個代理對象,負責調用被代理對象delegate的invoke方法,其中delegate參數目前是NativeMethodAccessorImpl對象,所以最終Method的invoke方法調用的是NativeMethodAccessorImpl對象invoke方法,實現如下:

這里用到了ReflectionFactory類中的inflationThreshold,當delegate調用了15次invoke方法之后,如果繼續調用就通過MethodAccessorGenerator類的generateMethod方法生成MethodAccessorImpl對象,并設置為delegate對象,這樣下次執行Method.invoke時,就調用新建的MethodAccessor對象的invoke()方法了。


這里需要注意的是:


generateMethod方法在生成MethodAccessorImpl對象時,會在內存中生成對應的字節碼,并調用ClassDefiner.defineClass創建對應的class對象,實現如下:

在ClassDefiner.defineClass方法實現中,每被調用一次都會生成一個DelegatingClassLoader類加載器對象

這里每次都生成新的類加載器,是為了性能考慮,在某些情況下可以卸載這些生成的類,因為類的卸載是只有在類加載器可以被回收的情況下才會被回收的,如果用了原來的類加載器,那可能導致這些新創建的類一直無法被卸載,從其設計來看本身就不希望這些類一直存在內存里的,在需要的時候有就行了。

轉載于:https://my.oschina.net/u/2441327/blog/872994

總結

以上是生活随笔為你收集整理的深入分析 Java 方法反射的实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。