Reflection générique obtenir la valeur du champ


132

J'essaie de recevoir la valeur du champ par réflexion. Le problème est que je ne connais pas le type de champs et que je dois le décider tout en obtenant la valeur.

Ce code résulte avec cette exception:

Impossible de définir le champ java.lang.String com .... fieldName sur 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);

J'ai essayé de lancer, mais j'obtiens des erreurs de compilation:

field.get((targetType)objectValue)

ou

targetType objectValue = targetType.newInstance();

Comment puis-je faire ceci?


4
En regardant l' API , l'argument de field.get()devrait être object, non objectValue.
akaIDIOT

Réponses:


144

Comme indiqué précédemment, vous devez utiliser:

Object value = field.get(objectInstance);

Une autre méthode, parfois préférée, consiste à appeler le getter dynamiquement. code d'exemple:

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

Sachez également que lorsque votre classe hérite d'une autre classe, vous devez déterminer de manière récursive le Field. par exemple, pour récupérer tous les champs d'une classe donnée;

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

1
il ne semble pas tout à fait vrai que vous deviez parcourir vous-même les super classes. Le c.getFields () ou c.getField () recherchera automatiquement le champ sur chaque interface d'outil et récursivement dans toutes les superclasses. Il suffit donc de passer à getX depuis getDeclaredX.
Przemysław Ładyński

3
En effet, la routine getFields () vous permettra de récupérer les champs de toutes les super classes et interfaces, mais uniquement les publiques. Habituellement, les champs sont rendus privés / protégés et sont exposés via des getters / setters.
Marius

@Marius, puis-je savoir quel est le package BaseValidationObject?
randytan

@Randytan, il est contenu dans mon référentiel de code privé, vous pouvez le remplacer par Object. La même chose s'applique aux appels statiques du Logger, remplacez-les par votre propre logger (instance).
Marius

@Marius la objectclasse n'a pas la méthode getMethods(). Un conseil?
randytan

127

Vous devez passer l' objet pour obtenir la méthode du champ , donc

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

6
connaissez-vous la raison pour laquelle l'objet doit être utilisé dans field.get (object) - le champ lui-même vient de cet objet, pourquoi en a-t-il encore besoin!?
serup

18
@serup Non, l'objet Field provient de l'objet Class, qui n'a aucun lien avec votre instance réelle. ( object.getClass()vous retournera cet objet Class)
Dmitry Spikhalskiy

1
objectdans l'extrait de code n'est pas défini, les lecteurs ne peuvent donc pas comprendre comment l'utiliser.
Ghilteras

@Ghilteras dans ce cas, ils ne devraient pas encore utiliser la réflexion et acquérir d'abord des compétences de base 🤷🏻‍♂️. La réflexion est un sujet suffisamment avancé pour ne pas expliquer qu'une variable objectsignifie notre objet / instance cible avec lequel nous travaillons. Je pense que les lecteurs sont en fait totalement d'accord avec ce que objectcontient cette réponse.
Dmitry Spikhalskiy le

@RajanPrasad Pas vraiment. Il y a un seul objet dans la question qui a un nom «objet». D'autres objets ont d'autres noms. La réponse est précise et adaptée aux questions et aux noms utilisés dans la question afin de rendre les choses aussi claires que possible. Si cela ne fonctionne pas pour vous - je n'ai aucune idée de comment le rendre plus clair et vous devriez essayer d'autres réponses ou probablement éviter la réflexion pour l'instant.
Dmitry Spikhalskiy

19

J'utilise les réflexions dans l'implémentation toString () de ma classe de préférence pour voir les membres de la classe et les valeurs (débogage simple et rapide).

Le code simplifié que j'utilise:

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

J'espère que cela aidera quelqu'un, car j'ai aussi cherché.


12

Bien que je ne sache pas vraiment ce que vous essayez de réaliser, j'ai repéré une erreur évidente dans votre code: Field.get()attend l'objet qui contient le champ comme argument, pas une valeur (possible) de ce champ. Donc vous devriez avoir field.get(object).

Puisque vous semblez rechercher la valeur du champ, vous pouvez l'obtenir comme suit:

Object objectValue = field.get(object);

Pas besoin d'instancier le type de champ et de créer une valeur vide / par défaut; ou peut-être qu'il y a quelque chose que j'ai manqué.


2
objectn'est pas défini, les lecteurs ne peuvent pas comprendre comment appliquer la réponse.
Ghilteras le

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

Vous appelez get avec le mauvais argument.

Ça devrait être:

Object value = field.get(object);

2
objectn'est pas défini, les lecteurs ne peuvent pas comprendre comment appliquer l'exemple dans la réponse
Ghilteras

2

Je poste ma solution dans Kotlin, mais elle peut également fonctionner avec des objets java. Je crée une extension de fonction pour que tout objet puisse utiliser cette fonction.

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

Jetez un œil à cette page 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));
`
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.