如何从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()
相关文章
相关标签/搜索