反射訪問屬性或方法時將Accessible設置為true

Java中通過反射執行一個方法的過程如下:獲取一個方法對象,然後根據isAccessible返回值確定是否能夠執行,如果返回值為false則需要調用setAccessible(true),最後再調用invoke執行方法,具體如下: 

反射訪問屬性或方法時將Accessible設置為true

此段代碼已經成了習慣用法:通過反射方法執行方法時,必須在invoke之前檢查Accessible屬性。這是一個好習慣,也確實該如此,但方法對象的Accessible屬性並不是用來決定是否可以訪問的,看如下代碼:

反射訪問屬性或方法時將Accessible設置為true

定義一個public類的public方法,這是一個沒有任何限制的方法,按照我們對Java語言的理解,此時doStuff方法可以被任何一個類訪問。我們編寫一個客戶端類來檢查該方法是否可以反射執行:

反射訪問屬性或方法時將Accessible設置為true

很簡單的反射操作,獲得一個方法,然後檢查是否可以訪問,最後執行方法輸出。讓我們來猜想一下結果:因為Foo類是public的,方法也是public的,全部都是最開放的訪問權限Accessible也應該等於true。但是運行結果卻是:

  Accessible:false

Do Stuff...

為什麼Accessible屬性會等於false?而且等於false還能執行?這是因為Accessible的屬性並不是我們語法層級理解的訪問權限,而是指是否更容易獲得,是否進行安全檢查。

我們知道,動態修改一個類或執行方法時都會受到Java安全體制的制約,而安全的處理是非常耗資源的(性能非常低),因此對於運行期要執行的方法或要修改的屬性就提供了Accessible可選項:由開發者決定是否要逃避安全體系的檢查。

閱讀源代碼是最好的理解方式,我們來看AccessibleObject類的源代碼,它提供了取消默認訪問控制檢查的功能。首先查看isAccessible方法,代碼如下:

反射訪問屬性或方法時將Accessible設置為true

AccessibleObject是Filed、Method、Constructor的父類,決定其是否可以快速訪問而不進行訪問控制檢查,在AccessibleObject類中是以override變量保存該值的,但是具體是否快速執行時在Method的invoke方法中決定的,源碼如下:

反射訪問屬性或方法時將Accessible設置為true

看了這段代碼,大家就清楚了:Accessible屬性只是用來判斷是否需要進行安全檢查的,如果不需要則直接執行,這就可以大幅度的提升系統性能了(當然了,取消了安全檢查,也可以運行private方法、訪問private屬性的)。經過測試,在大量的反射情況下,設置Accessible為true可以提高性能20倍左右。

AccessibleObject的其它兩個子類Field和Constructor與Method的情形類似:Accessible屬性決定Field和Constructor是否受訪問控制檢查。我們在設置Field或執行Constructor時,務必要設置Accessible為true,這並不僅僅是因為操作習慣的問題,還是為我們的系統性能考慮。

有討論,才有進步,大家各抒己見,讓每位同學學到不一樣的!


分享到:


相關文章: