我在第三方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中提取类,使用(例如) Jode或Jad对其进行反编译,更改字段(或添加访问器),然后针对原始.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()
来源:oschina
链接:https://my.oschina.net/u/3797416/blog/3160851