我在第三方JAR
設計的課程設計不佳,須要訪問其私有字段之一。 例如,爲何我須要選擇私有字段? 框架
class IWasDesignedPoorly { private Hashtable stuffIWant; } IWasDesignedPoorly obj = ...;
我如何使用反射來獲取stuffIWant
的價值? spa
爲了訪問私有字段,您須要從類的聲明字段中獲取它們,而後使其可訪問: 設計
Field f = obj.getClass().getDeclaredField("stuffIWant"); //NoSuchFieldException f.setAccessible(true); Hashtable iWantThis = (Hashtable) f.get(obj); //IllegalAccessException
編輯 :正如aperkins所評論的那樣 ,訪問字段,將其設置爲可訪問並獲取值都將拋出Exception
,儘管上面僅提到了您須要注意的全部檢查異常。 code
若是您請求的字段名稱與聲明的字段不對應,則將引起NoSuchFieldException
。 對象
obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException
若是該字段不可訪問(例如,若是它是私有的而且因爲缺乏f.setAccessible(true)
行而沒法訪問),則將拋出IllegalAccessException
。 get
若是嘗試訪問非字段類類型的對象上的字段,則可能拋出的RuntimeException
多是SecurityException
(若是JVM的SecurityManager
不容許您更改字段的可訪問性),或者是IllegalArgumentException
。 hash
f.get("BOB"); //will throw IllegalArgumentException, as String is of the wrong type
如oxbow_lakes所述,您可使用反射來繞過訪問限制(假設您的SecurityManager可讓您)。 it
就是說,若是此類設計得如此糟糕以致於使您訴諸於此類黑客,那麼也許您應該尋找替代方案。 固然,這個小技巧如今可能能夠爲您節省幾個小時,可是您要付出多少代價呢? io
反射不是解決問題的惟一方法(即訪問類/組件的私有功能/行爲) 編譯
另外一種解決方案是從.jar中提取類,使用(例如) Jode或Jad對其進行反編譯,更改字段(或添加訪問器),而後針對原始.jar對其進行從新編譯。 而後,將新.class放在.jar
以前的類路徑中,或將其從新插入.jar
。 (jar實用程序容許您提取並從新插入到現有的.jar中)
以下所述,這解決了訪問/更改私有狀態的普遍問題,而不是簡單地訪問/更改字段。
固然,這須要不要對.jar
進行簽名。
使用Soot Java Optimization框架直接修改字節碼。 http://www.sable.mcgill.ca/soot/
Soot徹底用Java編寫,而且可使用新的Java版本。
還沒有說起的另外一個選擇:使用Groovy 。 Groovy容許您訪問私有實例變量,這是該語言設計的反作用。 無論您在該領域是否有吸氣劑,您均可以使用
def obj = new IWasDesignedPoorly() def hashTable = obj.getStuffIWant()