Reflection generic erhält Feldwert

132

Ich versuche, Feldwert durch Reflexion zu erhalten. Das Problem ist, dass ich den Feldtyp nicht kenne und ihn entscheiden muss, während ich den Wert erhalte.

Dieser Code führt zu dieser Ausnahme:

Das Feld java.lang.String com .... fieldName kann nicht auf java.lang.String gesetzt werden

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

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

Object value = field.get(objectValue);

Ich habe versucht zu besetzen, aber ich erhalte Kompilierungsfehler:

field.get((targetType)objectValue)

oder

targetType objectValue = targetType.newInstance();

Wie kann ich das machen?

Ido Barash
quelle
4
Mit Blick auf die API , das Argument field.get()sollte sein object, nicht objectValue.
akaIDIOT

Antworten:

144

Wie zuvor beantwortet, sollten Sie verwenden:

Object value = field.get(objectInstance);

Ein anderer Weg, der manchmal bevorzugt wird, besteht darin, den Getter dynamisch aufzurufen. Beispielcode:

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

Beachten Sie auch, dass Sie das Feld rekursiv bestimmen müssen, wenn Ihre Klasse von einer anderen Klasse erbt. Zum Beispiel, um alle Felder einer bestimmten Klasse abzurufen.

    for (Class<?> c = someClass; c != null; c = c.getSuperclass())
    {
        Field[] fields = c.getDeclaredFields();
        for (Field classField : fields)
        {
            result.add(classField);
        }
    }
Marius
quelle
1
Es scheint nicht genau richtig zu sein, dass Sie selbst durch Superklassen iterieren müssen. Die c.getFields () oder c.getField () durchsuchen das Feld auf jeder Implementierungsschnittstelle automatisch und rekursiv durch alle Oberklassen. Es reicht also aus, von getDeclaredX zu getX zu wechseln.
Przemysław Ładyński
3
In der Tat können Sie mit der Routine getFields () die Felder für alle Superklassen und Schnittstellen abrufen, jedoch nur für die öffentlichen. Normalerweise werden Felder privat / geschützt gemacht und über Getter / Setter freigelegt.
Marius
@Marius, darf ich wissen, was das Paket ist BaseValidationObject?
Randytan
@ Randytan, das in meinem privaten Code-Repository enthalten ist, kann durch Object ersetzt werden. Gleiches gilt für die statischen Logger-Aufrufe. Ersetzen Sie diese durch Ihren eigenen Logger (Instanz).
Marius
@Marius die objectKlasse hat die Methode nicht getMethods(). Irgendwelche Ratschläge?
Randytan
127

Sie sollten das Pass - Objekt zu erhalten Methode des Feldes , so

  Field field = object.getClass().getDeclaredField(fieldName);    
  field.setAccessible(true);
  Object value = field.get(object);
Dmitry Spikhalskiy
quelle
6
Kennen Sie den Grund, warum das Objekt in field.get (Objekt) verwendet werden muss? Das Feld selbst stammt von diesem Objekt. Warum wird es erneut benötigt?
Serup
18
@serup Nein, das Feldobjekt stammt vom Klassenobjekt, das keine Verbindung zu Ihrer tatsächlichen Instanz hat. ( object.getClass()gibt Ihnen dieses
Klassenobjekt zurück
1
objectDas Snippet ist nicht definiert, sodass die Leser nicht verstehen können, wie es verwendet wird.
Ghilteras
@Ghilteras in diesem Fall sollten sie noch keine Reflexion verwenden und zuerst einige grundlegende Fähigkeiten erwerben 🤷🏻‍♂️. Reflexion ist ein Thema, das weit genug fortgeschritten ist, um nicht zu erklären, dass eine Variable objectunser Zielobjekt / unsere Zielinstanz bedeutet, mit der wir arbeiten. Ich denke, dass die Leser tatsächlich völlig in Ordnung sind mit dem, was objectin dieser Antwort steht.
Dmitry Spikhalskiy
@ RajanPrasad Nicht wirklich. Die Frage enthält ein einzelnes Objekt mit dem Namen "Objekt". Andere Objekte haben andere Namen. Die Antwort ist präzise und auf die Fragen und die Namen zugeschnitten, die in der Frage verwendet werden, um die Dinge so klar wie möglich zu machen. Wenn es bei Ihnen nicht funktioniert - ich habe keine Ahnung, wie ich es klarer machen kann, und Sie sollten andere Antworten ausprobieren oder wahrscheinlich noch keine Reflexion vermeiden.
Dmitry Spikhalskiy
18

Ich verwende die Reflexionen in der toString () - Implementierung meiner Präferenzklasse, um die Klassenmitglieder und Werte anzuzeigen (einfaches und schnelles Debuggen).

Der vereinfachte Code, den ich verwende:

@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();
}

Ich hoffe, dass es jemandem hilft, denn ich habe auch gesucht.

Silberschlumpf
quelle
12

Obwohl mir nicht wirklich klar ist, was Sie erreichen möchten, habe ich einen offensichtlichen Fehler in Ihrem Code festgestellt: Field.get()Erwartet das Objekt, das das Feld als Argument enthält, nicht einen (möglichen) Wert dieses Felds. Also solltest du haben field.get(object).

Da Sie scheinbar nach dem Feldwert suchen, können Sie diesen wie folgt erhalten:

Object objectValue = field.get(object);

Es ist nicht erforderlich, den Feldtyp zu instanziieren und einen leeren / Standardwert zu erstellen. oder vielleicht habe ich etwas verpasst.

Costi Ciudatu
quelle
2
objectist nicht definiert, Leser können nicht verstehen, wie die Antwort anzuwenden ist.
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();
 }
Rahul Sharma
quelle
4

Sie rufen get mit dem falschen Argument auf.

Es sollte sein:

Object value = field.get(object);
Seba
quelle
2
objectist nicht definiert, Leser können nicht verstehen, wie man das Beispiel in der Antwort
anwendet
2

Ich poste meine Lösung in Kotlin, aber sie kann auch mit Java-Objekten funktionieren. Ich erstelle eine Funktionserweiterung, damit jedes Objekt diese Funktion verwenden kann.

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

Schauen Sie sich diese Webseite an: https://www.geeksforgeeks.org/field-get-method-in-java-with-examples/

Isaias Carrera
quelle
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));
`
RANAJEET BARIK
quelle