108 votes

Comment boucler sur les attributs d'une classe en Java ?

Comment puis-je boucler sur les attributs d'une classe en java de manière dynamique.

Par exemple :

public class MyClass{
    private type1 att1;
    private type2 att2;
    ...

    public void function(){
        for(var in MyClass.Attributes){
            System.out.println(var.class);
        }
    }
}

Est-ce possible en Java ?

113voto

polygenelubricants Points 136838

Il n'y a pas de support linguistique pour faire ce que vous demandez.

Vous pouvez accéder de manière réfléchie aux membres d'un type à l'exécution en utilisant la réflexion (par exemple avec Class.getDeclaredFields() pour obtenir un tableau de Field), mais en fonction de ce que vous essayez de faire, cela peut ne pas être la meilleure solution.

Voir aussi

Questions liées


Exemple

Voici un exemple simple pour montrer seulement une partie de ce que la réflexion est capable de faire.

import java.lang.reflect.*;

public class DumpFields {
    public static void main(String[] args) {
        inspect(String.class);
    }
    static  void inspect(Class klazz) {
        Field[] fields = klazz.getDeclaredFields();
        System.out.printf("%d champs:%n", fields.length);
        for (Field field : fields) {
            System.out.printf("%s %s %s%n",
                Modifier.toString(field.getModifiers()),
                field.getType().getSimpleName(),
                field.getName()
            );
        }
    }
}

L'extrait ci-dessus utilise la réflexion pour inspecter tous les champs déclarés de la classe String ; il produit la sortie suivante :

7 champs :
private final char[] value
private final int offset
private final int count
private int hash
private static final long serialVersionUID
private static final ObjectStreamField[] serialPersistentFields
public static final Comparator CASE_INSENSITIVE_ORDER

Java efficace, 2e édition, Élément 53 : Privilégier les interfaces à la réflexion

Il s'agit d'extraits du livre :

Étant donné un objet Class, vous pouvez obtenir des instances Constructor, Method et Field représentant les constructeurs, méthodes et champs de la classe. [Ils] vous permettent de manipuler leurs homologues sous-jacents de manière réfléchie. Ce pouvoir, cependant, a un prix :

  • Vous perdez tous les avantages de la vérification à la compilation.
  • Le code requis pour effectuer l'accès réfléchi est maladroit et verbeux.
  • Les performances en souffrent.

En règle générale, les objets ne devraient pas être accédés de manière réfléchie dans des applications normales à l'exécution.

Il existe quelques applications sophistiquées qui nécessitent la réflexion. Des exemples incluent [...omis volontairement...] Si vous avez des doutes concernant le fait que votre application tombe dans une de ces catégories, elle ne le fait probablement pas.

48voto

Jörn Horstmann Points 18118

Accéder directement aux champs n'est pas vraiment une bonne pratique en java. Je suggérerais de créer des méthodes getter et setter pour les champs de votre bean, puis d'utiliser les classes Introspector et BeanInfo du package java.beans.

MyBean bean = new MyBean();
BeanInfo beanInfo = Introspector.getBeanInfo(MyBean.class);
for (PropertyDescriptor propertyDesc : beanInfo.getPropertyDescriptors()) {
    String propertyName = propertyDesc.getName();
    Object value = propertyDesc.getReadMethod().invoke(bean);
}

1 votes

Y a-t-il un moyen d'obtenir uniquement les propriétés de la classe bean, pas la classe? c'est-à-dire éviter que MyBean.class ne soit retourné par getPropertyDescriptors

0 votes

@if I understand you correctly, you can check for propertyDesc.getReadMethod().getDeclaringClass() != Object.class, or you can specify a class to stop analysis as the second parameter like getBeanInfo(MyBean.class, Object.class).

0 votes

Mon problème avec cette solution est que les getters (propertyDesc) sont triés alphabétiquement et j'ai besoin de l'ordre original des champs/getters.

30voto

Sean Patrick Floyd Points 109428

Alors que je suis d'accord avec la réponse de Jörn si votre classe est conforme à la spécification JavaBeans, voici une bonne alternative si ce n'est pas le cas et que vous utilisez Spring.

Spring a une classe nommée ReflectionUtils qui offre des fonctionnalités très puissantes, notamment doWithFields(classe, callback), une méthode de style visiteur qui vous permet d'itérer sur les champs d'une classe en utilisant un objet de rappel comme ceci :

public void analyze(Object obj){
    ReflectionUtils.doWithFields(obj.getClass(), field -> {

        System.out.println("Nom du champ : " + field.getName());
        field.setAccessible(true);
        System.out.println("Valeur du champ : "+ field.get(obj));

    });
}

Mais attention : la classe est étiquetée comme "à usage interne uniquement", ce qui est dommage à mon avis

19voto

rickey Points 1822

Moyen simple d'itérer sur les champs de classe et d'obtenir les valeurs de l'objet:

 Class c = obj.getClass();
 Field[] fields = c.getDeclaredFields();
 Map temp = new HashMap();

 for( Field field : fields ){
      try {
           temp.put(field.getName().toString(), field.get(obj));
      } catch (IllegalArgumentException e1) {
      } catch (IllegalAccessException e1) {
      }
 }

0 votes

Une classe peut-être ou n'importe quel objet.

0 votes

@Rickey Y a-t-il un moyen de définir une nouvelle valeur pour les attributs en parcourant chaque champ?

0 votes

@hyperfkcb Vous pouvez obtenir une exception de modification en essayant de modifier les valeurs des propriétés/champs sur lesquels vous itérez.

6voto

Tassos Bassoukos Points 6872

Java a Reflection (java.reflection.*), mais je suggérerais de se pencher sur une bibliothèque comme Apache Beanutils, cela rendra le processus beaucoup moins compliqué que d'utiliser la réflexion directement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X