Il valore di riflessione generico ottiene il campo


132

Sto cercando di ricevere il valore del campo tramite la riflessione. Il problema è che non conosco il tipo di campi e devo decidere mentre ottengo il valore.

Questo codice risulta con questa eccezione:

Impossibile impostare java.lang.String field com .... fieldName su 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);

Ho provato a trasmettere, ma ottengo errori di compilazione:

field.get((targetType)objectValue)

o

targetType objectValue = targetType.newInstance();

Come posso fare questo?


4
Guardando l' API , l'argomento field.get()dovrebbe essere object, no objectValue.
akaIDIOT,

Risposte:


144

Come già detto, dovresti usare:

Object value = field.get(objectInstance);

Un altro modo, a volte preferito, è chiamare il getter in modo dinamico. codice di esempio:

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

Inoltre, tieni presente che quando la tua classe eredita da un'altra classe, devi determinare ricorsivamente il Campo. ad esempio, per recuperare tutti i campi di una determinata classe;

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

1
non è esattamente vero che è necessario scorrere da soli le super classi. C.getFields () o c.getField () cercherà automaticamente il campo su ciascuna interfaccia dell'attrezzo e ricorsivamente attraverso tutte le superclassi. Quindi è sufficiente passare a getX da getDeclaredX.
Przemysław Ładyński,

3
In effetti, la routine getFields () ti permetterà di recuperare i campi per tutte le superclasse e le interfacce, ma solo quelle pubbliche. Di solito, i campi sono resi privati ​​/ protetti e sono esposti tramite getter / setter.
Marius,

@Marius, posso sapere cos'è il pacchetto BaseValidationObject?
randytan,

@Randytan, è contenuto nel mio repository di codice privato, puoi sostituirlo con Object. Lo stesso vale per le chiamate Logger statiche, sostituirle con il proprio logger (istanza).
Marius,

@Marius la objectclasse non ha il metodo getMethods(). Qualche consiglio?
randytan,

127

Dovresti passare l' oggetto per ottenere il metodo del campo , quindi

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

6
conosci il motivo per cui l'oggetto deve essere usato in field.get (oggetto) - il campo stesso proviene da quell'oggetto, perché ne ha bisogno di nuovo !?
serup,

18
@serup No, l'oggetto Field proviene dall'oggetto Class, che non ha alcuna connessione con l'istanza effettiva. ( object.getClass()ti restituirà questo oggetto Classe)
Dmitry Spikhalskiy il

1
objectnello snippet non è definito, quindi i lettori non possono capire come usarlo.
Ghilteras,

@Ghilteras in quel caso, non dovrebbero ancora usare la riflessione e ottenere prima alcune abilità di base 🤷🏻‍♂️. La riflessione è un argomento sufficientemente avanzato per non spiegare che una variabile objectsignifica il nostro oggetto / istanza target con cui lavoriamo. Penso che i lettori stiano davvero bene con ciò che è objectpresente in questa risposta.
Dmitry Spikhalskiy,

@RajanPrasad Non proprio. C'è un singolo oggetto nella domanda che ha un nome 'oggetto'. Altri oggetti hanno altri nomi. La risposta è precisa e su misura per le domande e per i nomi utilizzati nella domanda per rendere le cose il più chiare possibile. Se non funziona per te, non ho idea di come renderlo più chiaro e dovresti provare altre risposte o probabilmente evitare la riflessione ancora.
Dmitry Spikhalskiy il

19

Uso i riflessi nell'implementazione toString () della mia classe di preferenze per vedere i membri ei valori della classe (debug semplice e veloce).

Il codice semplificato che sto usando:

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

Spero che possa aiutare qualcuno, perché ho anche cercato.


12

Anche se non mi è chiaro cosa stai cercando di ottenere, ho notato un errore evidente nel tuo codice: si Field.get()aspetta l'oggetto che contiene il campo come argomento, non un valore (possibile) di quel campo. Quindi dovresti avere field.get(object).

Poiché sembra che tu stia cercando il valore del campo, puoi ottenerlo come:

Object objectValue = field.get(object);

Non è necessario creare un'istanza del tipo di campo e creare un valore vuoto / predefinito; o forse c'è qualcosa che mi mancava.


2
objectnon è definito, i lettori non possono capire come applicare la risposta.
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

Stai chiamando get con l'argomento sbagliato.

Dovrebbe essere:

Object value = field.get(object);

2
objectnon è definito, i lettori non riescono a capire come applicare l'esempio nella risposta
Ghilteras

2

Pubblico la mia soluzione in Kotlin, ma può funzionare anche con oggetti Java. Creo un'estensione di funzione in modo che qualsiasi oggetto possa utilizzare questa funzione.

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

Dai un'occhiata a questa pagina web: 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));
`
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.