我在第三方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()