反射通用获取字段值


132

我试图通过反射接收字段值。问题是我不知道字段类型,必须在获取值时决定它。

这段代码会导致以下异常:

无法将java.lang.String字段com .... fieldName设置为java.lang.String

Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);

Class<?> targetType = field.getType();
Object objectValue = targetType.newInstance();

Object value = field.get(objectValue);

我尝试进行转换,但出现编译错误:

field.get((targetType)objectValue)

要么

targetType objectValue = targetType.newInstance();

我怎样才能做到这一点?


4
看一下API,to的参数field.get()应该是object,而不是objectValue
akaIDIOT 2012年

Answers:


144

像之前回答的那样,您应该使用:

Object value = field.get(objectInstance);

有时更喜欢的另一种方法是动态调用getter。示例代码:

public static Object runGetter(Field field, BaseValidationObject o)
{
    // MZ: Find the correct method
    for (Method method : o.getMethods())
    {
        if ((method.getName().startsWith("get")) && (method.getName().length() == (field.getName().length() + 3)))
        {
            if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase()))
            {
                // MZ: Method found, run it
                try
                {
                    return method.invoke(o);
                }
                catch (IllegalAccessException e)
                {
                    Logger.fatal("Could not determine method: " + method.getName());
                }
                catch (InvocationTargetException e)
                {
                    Logger.fatal("Could not determine method: " + method.getName());
                }

            }
        }
    }


    return null;
}

另请注意,当您的类继承自另一个类时,您需要递归确定Field。例如,获取给定类的所有字段;

    for (Class<?> c = someClass; c != null; c = c.getSuperclass())
    {
        Field[] fields = c.getDeclaredFields();
        for (Field classField : fields)
        {
            result.add(classField);
        }
    }

1
您需要自己遍历超类似乎并不完全正确。c.getFields()或c.getField()将自动在每个机具接口上搜索字段,并通过所有超类递归搜索。因此,从getDeclaredX切换到getX就足够了。
普热Ładyński

3
实际上,getFields()例程将允许您获取所有超类和接口的字段,但只能获取公共的类和接口的字段。通常,将字段设置为私有/受保护,并通过getter / setter公开。
Marius 2015年

@Marius,请问包裹是BaseValidationObject什么?
randytan 2015年

@Randytan,包含在我的私有代码存储库中,您可以将其替换为Object。静态Logger调用也是如此,将其替换为您自己的logger(实例)。
Marius 2015年

@Marius该object课程没有方法getMethods()。有什么建议吗?
randytan 2015年

127

您应该传递对象获取字段的方法,因此

  Field field = object.getClass().getDeclaredField(fieldName);    
  field.setAccessible(true);
  Object value = field.get(object);

6
您知道为什么必须在field.get(object)中使用对象的原因-字段本身来自该对象,为什么它再次需要它!
serup

18
@serup否,Field对象来自Class对象,该Class对象与您的实际实例没有任何关系。(object.getClass()将为您返回该Class对象)
Dmitry Spikhalskiy

1
object代码段中没有定义,因此读者无法理解如何使用它。
Ghilteras

在这种情况下,@ Ghilteras不应该使用反射,而是先获得一些基本技能。反射是一个足够高级的主题,无法解释变量object意味着我们使用的目标对象/实例。我认为读者实际上object对此答案的理解是完全可以的。
Dmitry Spikhalskiy

@RajanPrasad不是。问题中有一个对象名为“对象”。其他对象有其他名称。答案是精确的,并且针对问题和问题中使用的名称进行了量身定制,以使事情变得尽可能清晰。如果它对您不起作用-我不知道如何使其更加清晰,您应该尝试其他答案,或者可能还应该避免反思。
德米特里·斯皮哈尔斯基

18

我使用首选项类的toString()实现中的反射来查看类的成员和值(简单而快速的调试)。

我正在使用的简化代码:

@Override
public String toString() {
    StringBuilder sb = new StringBuilder();

    Class<?> thisClass = null;
    try {
        thisClass = Class.forName(this.getClass().getName());

        Field[] aClassFields = thisClass.getDeclaredFields();
        sb.append(this.getClass().getSimpleName() + " [ ");
        for(Field f : aClassFields){
            String fName = f.getName();
            sb.append("(" + f.getType() + ") " + fName + " = " + f.get(this) + ", ");
        }
        sb.append("]");
    } catch (Exception e) {
        e.printStackTrace();
    }

    return sb.toString();
}

我希望它会对某人有所帮助,因为我也进行了搜索。


12

尽管我不清楚您要实现的目标,但我在您的代码中发现了一个明显的错误: Field.get()期望包含该字段的对象作为参数,而不是该字段的某些(可能)值。所以你应该有field.get(object)

由于您似乎正在寻找字段值,因此可以通过以下方式获得该值:

Object objectValue = field.get(object);

无需实例化字段类型并创建一些空/默认值;也许我错过了一些东西。


2
object未定义,读者无法理解如何应用答案。
Ghilteras

10
 Integer typeValue = 0;
 try {
     Class<Types> types = Types.class;
     java.lang.reflect.Field field = types.getDeclaredField("Type");
     field.setAccessible(true);
     Object value = field.get(types);
     typeValue = (Integer) value;
 } catch (Exception e) {
     e.printStackTrace();
 }

4

您正在调用带有错误参数的get。

它应该是:

Object value = field.get(object);

2
object未定义,读者无法理解如何在答案中应用示例
Ghilteras

2

我将解决方案发布在Kotlin中,但它也可以与java对象一起使用。我创建了一个功能扩展,因此任何对象都可以使用此功能。

fun Any.iterateOverComponents() {

val fields = this.javaClass.declaredFields

fields.forEachIndexed { i, field ->

    fields[i].isAccessible = true
    // get value of the fields
    val value = fields[i].get(this)

    // print result
    Log.w("Msg", "Value of Field "
            + fields[i].name
            + " is " + value)
}}

看看这个网页:https : //www.geeksforgeeks.org/field-get-method-in-java-with-examples/


1
    ` 
//Here is the example I used for get the field name also the field value
//Hope This will help to someone
TestModel model = new TestModel ("MyDate", "MyTime", "OUT");
//Get All the fields of the class
 Field[] fields = model.getClass().getDeclaredFields();
//If the field is private make the field to accessible true
fields[0].setAccessible(true);
//Get the field name
  System.out.println(fields[0].getName());
//Get the field value
System.out.println(fields[0].get(model));
`
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.