如何從Java中的其餘類讀取私有字段的值?

我在第三方JAR設計的課程設計不佳,須要訪問其私有字段之一。 例如,爲何我須要選擇私有字段? 框架

class IWasDesignedPoorly {
    private Hashtable stuffIWant;
}

IWasDesignedPoorly obj = ...;

我如何使用反射來獲取stuffIWant的價值? spa


#1樓

爲了訪問私有字段,您須要從類的聲明字段中獲取它們,而後使其可訪問: 設計

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)行而沒法訪問),則將拋出IllegalAccessExceptionget

若是嘗試訪問非字段類類型的對象上的字段,則可能拋出的RuntimeException多是SecurityException (若是JVM的SecurityManager不容許您更改字段的可訪問性),或者是IllegalArgumentExceptionhash

f.get("BOB"); //will throw IllegalArgumentException, as String is of the wrong type

#2樓

如oxbow_lakes所述,您可使用反射來繞過訪問限制(假設您的SecurityManager可讓您)。 it

就是說,若是此類設計得如此糟糕以致於使您訴諸於此類黑客,那麼也許您應該尋找替代方案。 固然,這個小技巧如今可能能夠爲您節省幾個小時,可是您要付出多少代價呢? io


#3樓

反射不是解決問題的惟一方法(即訪問類/組件的私有功能/行爲) 編譯

另外一種解決方案是從.jar中提取類,使用(例如) JodeJad對其進行反編譯,更改字段(或添加訪問器),而後針對原始.jar對其進行從新編譯。 而後,將新.class放在.jar以前的類路徑中,或將其從新插入.jar 。 (jar實用程序容許您提取並從新插入到現有的.jar中)

以下所述,這解決了訪問/更改私有狀態的普遍問題,而不是簡單地訪問/更改字段。

固然,這須要不要對.jar進行簽名。


#4樓

使用Soot Java Optimization框架直接修改字節碼。 http://www.sable.mcgill.ca/soot/

Soot徹底用Java編寫,而且可使用新的Java版本。


#5樓

還沒有說起的另外一個選擇:使用Groovy 。 Groovy容許您訪問私有實例變量,這是該語言設計的反作用。 無論您在該領域是否有吸氣劑,您均可以使用

def obj = new IWasDesignedPoorly()
def hashTable = obj.getStuffIWant()
相關文章
相關標籤/搜索