如何从Java中的其他类读取私有字段的值?

爱⌒轻易说出口 提交于 2020-02-27 05:02:30

我在第三方JAR设计的课程设计不佳,需要访问其私有字段之一。 例如,为什么我需要选择私有字段?

class IWasDesignedPoorly {
    private Hashtable stuffIWant;
}

IWasDesignedPoorly obj = ...;

我如何使用反射来获取stuffIWant的价值?


#1楼

为了访问私有字段,您需要从类的声明字段中获取它们,然后使其可访问:

Field f = obj.getClass().getDeclaredField("stuffIWant"); //NoSuchFieldException
f.setAccessible(true);
Hashtable iWantThis = (Hashtable) f.get(obj); //IllegalAccessException

编辑 :正如aperkins所评论的那样 ,访问字段,将其设置为可访问并获取值都将抛出Exception ,尽管上面仅提到了您需要注意的所有检查异常。

如果您请求的字段名称与声明的字段不对应,则将引发NoSuchFieldException

obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException

如果该字段不可访问(例如,如果它是私有的并且由于缺少f.setAccessible(true)行而无法访问),则将抛出IllegalAccessException

如果尝试访问非字段类类型的对象上的字段,则可能抛出的RuntimeException可能是SecurityException (如果JVM的SecurityManager不允许您更改字段的可访问性),或者是IllegalArgumentException

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

#2楼

如oxbow_lakes所述,您可以使用反射来绕过访问限制(假设您的SecurityManager可以让您)。

就是说,如果此类设计得如此糟糕以至于使您诉诸于此类黑客,那么也许您应该寻找替代方案。 当然,这个小技巧现在可能可以为您节省几个小时,但是您要付出多少代价呢?


#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()
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!