Java 反射 - 访问受保护的字段
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/735230/
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
Java reflection - access protected field
提问by Moro
How can I access an inherited protected field from an object by reflection?
如何通过反射从对象访问继承的受保护字段?
采纳答案by kenj0418
Two issues you may be having issues with - the field might not be accessible normally (private), and it's not in the class you are looking at, but somewhere up the hierarchy.
您可能遇到的两个问题 - 该字段可能无法正常访问(私有),并且它不在您正在查看的类中,而是在层次结构的某个位置。
Something like this would work even with those issues:
即使遇到这些问题,这样的事情也能奏效:
public class SomeExample {
public static void main(String[] args) throws Exception{
Object myObj = new SomeDerivedClass(1234);
Class myClass = myObj.getClass();
Field myField = getField(myClass, "value");
myField.setAccessible(true); //required if field is not normally accessible
System.out.println("value: " + myField.get(myObj));
}
private static Field getField(Class clazz, String fieldName)
throws NoSuchFieldException {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
Class superClass = clazz.getSuperclass();
if (superClass == null) {
throw e;
} else {
return getField(superClass, fieldName);
}
}
}
}
class SomeBaseClass {
private Integer value;
SomeBaseClass(Integer value) {
this.value = value;
}
}
class SomeDerivedClass extends SomeBaseClass {
SomeDerivedClass(Integer value) {
super(value);
}
}
回答by Maurice Perry
field = myclass.getDeclaredField("myname");
field.setAccessible(true);
field.set(myinstance, newvalue);
回答by Tom Hawtin - tackline
Do you perhaps mean from a different object an untrusted context with a SecurityManager
set? That would break the type system, so you can't. From a trusted context, you can call setAccessible
to defeat the type system. Ideally, don't use reflection.
您可能是从不同的对象中表示具有SecurityManager
集合的不受信任的上下文吗?那会破坏类型系统,所以你不能。从受信任的上下文中,您可以调用setAccessible
来击败类型系统。理想情况下,不要使用反射。
回答by Craig Otis
You could do something like...
你可以做一些像...
Class clazz = Class.forName("SuperclassObject");
Field fields[] = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.getName().equals("fieldImLookingFor")) {
field.set...() // ... should be the type, eg. setDouble(12.34);
}
}
You might also need to change the accessibility, as noted in Maurice's answer.
您可能还需要更改可访问性,如 Maurice 的回答中所述。
回答by jweyrich
Use reflection to access the members of the class instance, make them accessible and set their respective values. Of course you'd have to know the name of each member you want to change, but I guess that won't be a problem.
使用反射访问类实例的成员,使它们可访问并设置它们各自的值。当然你必须知道你想改变的每个成员的名字,但我想这不会有问题。
public class ReflectionUtil {
public static Field getField(Class clazz, String fieldName) throws NoSuchFieldException {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
Class superClass = clazz.getSuperclass();
if (superClass == null) {
throw e;
} else {
return getField(superClass, fieldName);
}
}
}
public static void makeAccessible(Field field) {
if (!Modifier.isPublic(field.getModifiers()) ||
!Modifier.isPublic(field.getDeclaringClass().getModifiers()))
{
field.setAccessible(true);
}
}
}
public class Application {
public static void main(String[] args) throws Exception {
KalaGameState obj = new KalaGameState();
Field field = ReflectionUtil.getField(obj.getClass(), 'turn');
ReflectionUtil.makeAccessible(field);
field.setInt(obj, 666);
System.out.println("turn is " + field.get(obj));
}
}
回答by Knubo
I didn't want to drag in more libraries so I made a pure one that worked for me. It is an extension of one of the methods from jweyrich:
我不想拖入更多的库,所以我制作了一个对我有用的纯库。它是 jweyrich 方法之一的扩展:
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
public abstract class POJOFiller {
static final Random random = new Random();
public static void fillObject(Object ob) {
Class<? extends Object> clazz = ob.getClass();
do {
Field[] fields = clazz.getDeclaredFields();
fillForFields(ob, fields);
if (clazz.getSuperclass() == null) {
return;
}
clazz = clazz.getSuperclass();
} while (true);
}
private static void fillForFields(Object ob, Field[] fields) {
for (Field field : fields) {
field.setAccessible(true);
if(Modifier.isFinal(field.getModifiers())) {
continue;
}
try {
field.set(ob, generateRandomValue(field.getType()));
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
}
static Object generateRandomValue(Class<?> fieldType) {
if (fieldType.equals(String.class)) {
return UUID.randomUUID().toString();
} else if (Date.class.isAssignableFrom(fieldType)) {
return new Date(System.currentTimeMillis());
} else if (Number.class.isAssignableFrom(fieldType)) {
return random.nextInt(Byte.MAX_VALUE) + 1;
} else if (fieldType.equals(Integer.TYPE)) {
return random.nextInt();
} else if (fieldType.equals(Long.TYPE)) {
return random.nextInt();
} else if (Enum.class.isAssignableFrom(fieldType)) {
Object[] enumValues = fieldType.getEnumConstants();
return enumValues[random.nextInt(enumValues.length)];
} else if(fieldType.equals(Integer[].class)) {
return new Integer[] {random.nextInt(), random.nextInt()};
}
else {
throw new IllegalArgumentException("Cannot generate for " + fieldType);
}
}
}
回答by pds
A generic utility method to run any getter in this or any superclass.
在此或任何超类中运行任何 getter 的通用实用方法。
Adapted from Marius'sanswer.
改编自马吕斯的回答。
public static Object RunGetter(String fieldname, Object o){
Object result = null;
boolean found = false;
//Search this and all superclasses:
for (Class<?> clas = o.getClass(); clas != null; clas = clas.getSuperclass()){
if(found){
break;
}
//Find the correct method:
for (Method method : clas.getDeclaredMethods()){
if(found){
break;
}
//Method found:
if ((method.getName().startsWith("get")) && (method.getName().length() == (fieldname.length() + 3))){
if (method.getName().toLowerCase().endsWith(fieldname.toLowerCase())){
try{
result = method.invoke(o); //Invoke Getter:
found = true;
} catch (IllegalAccessException | InvocationTargetException ex){
Logger.getLogger("").log(Level.SEVERE, "Could not determine method: " + method.getName(), ex);
}
}
}
}
}
return result;
}
Hopefully that is useful to someone.
希望这对某人有用。
回答by Ewebs
If you are just getting the protected field
如果您只是获得受保护的字段
Field protectedfield = Myclazz.class.getSuperclass().getDeclaredField("num");
If you are using Eclipse Ctrl+ Spacewill bring up a list of methods when you type a "." after the object
如果您使用 Eclipse Ctrl+Space将在您键入“.”时显示一个方法列表。在对象之后
回答by mrts
Use FieldUtils.writeField(object, "fieldname", value, true)
or readField(object, "fieldname", true)
from Apache Commons lang3.
使用FieldUtils.writeField(object, "fieldname", value, true)
或readField(object, "fieldname", true)
来自Apache Commons lang3。
回答by Steve Chambers
If using Spring, ReflectionTestUtilsprovides some handy tools that help out here with minimal effort.
如果使用 Spring,ReflectionTestUtils提供了一些方便的工具,可以以最少的努力在这里提供帮助。
For example, to get a protected field value that is known to be an int
:
例如,要获取已知为 的受保护字段值int
:
int theIntValue = (int)ReflectionTestUtils.getField(theClass, "theProtectedIntField");
Or alternatively to set this field's value:
或者设置此字段的值:
ReflectionTestUtils.setField(theClass, "theProtectedIntField", theIntValue);