Отражение общего значения поля получения

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 , аргумент field.get()должен быть object, а не objectValue.
akaIDIOT

Ответы:

144

Как уже было сказано ранее, вы должны использовать:

Object value = field.get(objectInstance);

Другой способ, который иногда предпочитают, - это динамический вызов геттера. пример кода:

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;
}

Также имейте в виду, что когда ваш класс наследуется от другого класса, вам необходимо рекурсивно определить поле. например, чтобы получить все поля данного класса;

    for (Class<?> c = someClass; c != null; c = c.getSuperclass())
    {
        Field[] fields = c.getDeclaredFields();
        for (Field classField : fields)
        {
            result.add(classField);
        }
    }
Marius
источник
1
кажется не совсем верным, что вам нужно самостоятельно перебирать суперклассы. C.getFields () или c.getField () будет автоматически искать поле на каждом интерфейсе реализации и рекурсивно по всем суперклассам. Так что достаточно просто переключиться на getX из getDeclaredX.
Przemysław adyński
3
Действительно, процедура getFields () позволит вам получить поля для всех суперклассов и интерфейсов, но только для общедоступных. Обычно поля делаются закрытыми / защищенными и предоставляются через геттеры / сеттеры.
Мариус
@Marius, могу я узнать, что это за пакет BaseValidationObject?
Randytan
@Randytan, он содержится в моем частном репозитории кода, вы можете заменить его на Object. То же самое относится к статическим вызовам регистратора, замените их своим собственным регистратором (экземпляром).
Мариус
@Marius у objectкласса нет метода getMethods(). Любой совет?
randytan
127

Вы должны передать объект, чтобы получить метод поля , поэтому

  Field field = object.getClass().getDeclaredField(fieldName);    
  field.setAccessible(true);
  Object value = field.get(object);
Дмитрий Спихальский
источник
6
знаете ли вы причину, по которой объект должен использоваться в field.get (object) - само поле происходит от этого объекта, зачем оно ему снова нужно !?
serup
18
@serup Нет, объект Field происходит из объекта Class, который не связан с вашим фактическим экземпляром. ( object.getClass()вернет вам этот объект класса)
Дмитрий Спихальский
1
objectво фрагменте не определен, поэтому читатели не могут понять, как его использовать.
Гилтерас,
@Ghilteras, в таком случае им пока не следует использовать рефлексию и сначала получить базовые навыки 🤷🏻‍♂️. Отражение - достаточно сложная тема, чтобы не объяснять, что переменная objectозначает наш целевой объект / экземпляр, с которым мы работаем. Я думаю, что читателей на самом деле совершенно устраивает то, что содержится objectв этом ответе.
Дмитрий Спихальский,
@RajanPrasad Не совсем. В вопросе есть единственный объект с именем «объект». Остальные объекты имеют другие названия. Ответ точен и адаптирован к вопросам и именам, которые используются в вопросе, чтобы прояснить ситуацию. Если это не сработает для вас - я не знаю, как сделать это более понятным, и вам следует попробовать другие ответы или, возможно, пока что избегать размышлений.
Дмитрий Спихальский
19

Я использую отражения в реализации 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();
}

Я надеюсь, что это кому-то поможет, потому что я тоже искал.

silversmurf
источник
12

Хотя мне не совсем понятно, чего вы пытаетесь достичь, я обнаружил очевидную ошибку в вашем коде: Field.get()ожидает объект, который содержит поле в качестве аргумента, а не какое-то (возможное) значение этого поля. Так и должно быть field.get(object).

Поскольку вы, похоже, ищете значение поля, вы можете получить его как:

Object objectValue = field.get(object);

Нет необходимости создавать экземпляр типа поля и создавать какое-то пустое / значение по умолчанию; или, может быть, я что-то упустил.

Кости Сьюдату
источник
2
objectне определено, читатели не могут понять, как применить ответ.
Гилтерас,
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

Вы призываете получить неправильный аргумент.

Так должно быть:

Object value = field.get(object);
Seba
источник
2
objectне определено, читатели не могут понять, как применить пример в ответе
Гилтерас,
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));
`
РАНАДЖИТ БАРИК
источник