如何从 Java 中的不同类读取私有字段的值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1196192/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to read the value of a private field from a different class in Java?
提问by Frank Krueger
I have a poorly designed class in a 3rd-party JAR
and I need to access one of its privatefields. For example,
why should I need to choose private field is it necessary?
我在第 3 方中有一个设计不佳的类JAR
,我需要访问它的一个私有字段。例如,为什么我需要选择私有字段是必要的吗?
class IWasDesignedPoorly {
private Hashtable stuffIWant;
}
IWasDesignedPoorly obj = ...;
How can I use reflection to get the value of stuffIWant
?
如何使用反射来获取 的值stuffIWant
?
采纳答案by oxbow_lakes
In order to access private fields, you need to get them from the class's declaredfields and then make them accessible:
为了访问私有字段,您需要从类的声明字段中获取它们,然后使它们可访问:
Field f = obj.getClass().getDeclaredField("stuffIWant"); //NoSuchFieldException
f.setAccessible(true);
Hashtable iWantThis = (Hashtable) f.get(obj); //IllegalAccessException
EDIT: as has been commented by aperkins, both accessing the field, setting it as accessible and retrieving the value can throw Exception
s, although the only checkedexceptions you need to be mindful of are commented above.
编辑:正如aperkins所评论的那样,访问该字段、将其设置为可访问和检索值都可以抛出Exception
s,尽管上面评论了您需要注意的唯一检查异常。
The NoSuchFieldException
would be thrown if you asked for a field by a name which did not correspond to a declared field.
在NoSuchFieldException
如果你问一个字段由不符合声明的字段的名称将被抛出。
obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException
The IllegalAccessException
would be thrown if the field was not accessible (for example, if it is private and has not been made accessible via missing out the f.setAccessible(true)
line.
该IllegalAccessException
会如果字段是不可访问(被抛出例如,如果是私人和通过失踪了尚未作出访问f.setAccessible(true)
线。
The RuntimeException
s which may be thrown are either SecurityException
s (if the JVM's SecurityManager
will not allow you to change a field's accessibility), or IllegalArgumentException
s, if you try and access the field on an object not of the field's class's type:
该RuntimeException
可抛出s为要么SecurityException
S(如果JVM的SecurityManager
将不允许你改变一个字段的可访问性),或IllegalArgumentException
S,如果你尝试接入领域的对象不是字段的类的类型上:
f.get("BOB"); //will throw IllegalArgumentException, as String is of the wrong type
回答by Laurence Gonsalves
As oxbow_lakes mentions, you can use reflection to get around the access restrictions (assuming your SecurityManager will let you).
正如 oxbow_lakes 所提到的,您可以使用反射来绕过访问限制(假设您的 SecurityManager 允许您)。
That said, if this class is so badly designed that it makes you resort to such hackery, maybe you should look for an alternative. Sure this little hack might be saving you a few hours now, but how much will it cost you down the road?
也就是说,如果这个课程设计得如此糟糕以至于让你诉诸于这种黑客,也许你应该寻找替代品。当然,这个小技巧现在可能会为您节省几个小时,但是以后会花多少钱?
回答by Brian Agnew
Reflection isn't the only way to resolve your issue (which is to access the private functionality/behaviour of a class/component)
反射不是解决问题的唯一方法(即访问类/组件的私有功能/行为)
An alternative solution is to extract the class from the .jar, decompile it using (say) Jodeor Jad, change the field (or add an accessor), and recompile it against the original .jar. Then put the new .class ahead of the .jar
in the classpath, or reinsert it in the .jar
. (the jar utility allows you to extract and reinsert to an existing .jar)
另一种解决方案是从 .jar 中提取类,使用(例如)Jode或Jad对其进行反编译,更改字段(或添加访问器),然后针对原始 .jar 重新编译它。然后将新的 .class 放在.jar
类路径中的 之前,或将其重新插入.jar
. (jar 实用程序允许您提取并重新插入现有的 .jar)
As noted below, this resolves the wider issue of accessing/changing private state rather than simply accessing/changing a field.
如下所述,这解决了访问/更改私有状态而不是简单地访问/更改字段的更广泛问题。
This requires the .jar
not to be signed, of course.
.jar
当然,这要求不要签名。
回答by pcpratts
Use the Soot Java Optimization framework to directly modify the bytecode. http://www.sable.mcgill.ca/soot/
使用 Soot Java Optimization 框架直接修改字节码。 http://www.sable.mcgill.ca/soot/
Soot is completely written in Java and works with new Java versions.
Soot 完全用 Java 编写,可与新的 Java 版本配合使用。
回答by lucas
One other option that hasn't been mentioned yet: use Groovy. Groovy allows you to access private instance variables as a side effect of the design of the language. Whether or not you have a getter for the field, you can just use
另一种尚未提及的选项:使用Groovy。Groovy 允许您访问私有实例变量作为语言设计的副作用。无论您是否有该领域的吸气剂,您都可以使用
def obj = new IWasDesignedPoorly()
def hashTable = obj.getStuffIWant()
回答by yegor256
Try FieldUtils
from apache commons-lang3:
FieldUtils
从 apache commons-lang3尝试:
FieldUtils.readField(object, fieldName, true);
回答by Simmant
Using the Reflection in Javayou can access all the private/public
fields and methods of one class to another .But as per the Oracledocumentationin the section drawbacksthey recommended that :
使用Java 中的反射,您可以private/public
将一个类的所有字段和方法访问到另一个类。但根据Oracle文档中的缺点部分,他们建议:
"Since reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects, which may render code dysfunctional and may destroy portability. Reflective code breaks abstractions and therefore may change behavior with upgrades of the platform"
“由于反射允许代码执行在非反射代码中是非法的操作,例如访问私有字段和方法,使用反射会导致意想不到的副作用,这可能会使代码功能失调并可能破坏可移植性。反射代码打破抽象,因此可能会随着平台的升级而改变行为”
here is following code snapts to demonstrate basic concepts of Reflection
这是以下代码快照以演示反射的基本概念
Reflection1.java
反射1.java
public class Reflection1{
private int i = 10;
public void methoda()
{
System.out.println("method1");
}
public void methodb()
{
System.out.println("method2");
}
public void methodc()
{
System.out.println("method3");
}
}
Reflection2.java
反射2.java
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Reflection2{
public static void main(String ar[]) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
Method[] mthd = Reflection1.class.getMethods(); // for axis the methods
Field[] fld = Reflection1.class.getDeclaredFields(); // for axis the fields
// Loop for get all the methods in class
for(Method mthd1:mthd)
{
System.out.println("method :"+mthd1.getName());
System.out.println("parametes :"+mthd1.getReturnType());
}
// Loop for get all the Field in class
for(Field fld1:fld)
{
fld1.setAccessible(true);
System.out.println("field :"+fld1.getName());
System.out.println("type :"+fld1.getType());
System.out.println("value :"+fld1.getInt(new Reflaction1()));
}
}
}
Hope it will help.
希望它会有所帮助。
回答by xtof54
Just an additional note about reflection: I have observed in some special cases, when several classes with the same name exist in different packages, that reflection as used in the top answer may fail to pick the correct class from the object. So if you know what is the package.class of the object, then it's better to access its private field values as follows:
关于反射的附加说明:我在一些特殊情况下观察到,当不同包中存在多个同名的类时,顶级答案中使用的反射可能无法从对象中选择正确的类。因此,如果您知道对象的 package.class 是什么,那么最好按如下方式访问其私有字段值:
org.deeplearning4j.nn.layers.BaseOutputLayer ll = (org.deeplearning4j.nn.layers.BaseOutputLayer) model.getLayer(0);
Field f = Class.forName("org.deeplearning4j.nn.layers.BaseOutputLayer").getDeclaredField("solver");
f.setAccessible(true);
Solver s = (Solver) f.get(ll);
(This is the example class that was not working for me)
(这是对我不起作用的示例类)
回答by Luke Hutchison
You need to do the following:
您需要执行以下操作:
private static Field getField(Class<?> cls, String fieldName) {
for (Class<?> c = cls; c != null; c = c.getSuperclass()) {
try {
final Field field = c.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (final NoSuchFieldException e) {
// Try parent
} catch (Exception e) {
throw new IllegalArgumentException(
"Cannot access field " + cls.getName() + "." + fieldName, e);
}
}
throw new IllegalArgumentException(
"Cannot find field " + cls.getName() + "." + fieldName);
}
回答by Steve Chambers
If using Spring, ReflectionTestUtilsprovides some handy tools that help out here with minimal effort. It's described as being "for use in unit and integration testing scenarios". There is also a similar class named ReflectionUtilsbut this is described as "Only intended for internal use"- see this answerfor an interpretation of what this means.
如果使用 Spring,ReflectionTestUtils提供了一些方便的工具,可以以最少的努力在这里提供帮助。它被描述为“用于单元和集成测试场景”。还有一个名为ReflectionUtils的类似类,但它被描述为“仅供内部使用”- 请参阅此答案以了解其含义。
To address the posted example:
要解决发布的示例:
Hashtable iWantThis = (Hashtable)ReflectionTestUtils.getField(obj, "stuffIWant");