web-dev-qa-db-fra.com

Comment boucler sur un attribut de classe en Java?

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

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?

68
Zakaria

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

Vous pouvez accéder de façon réfléchie aux membres d’un type lors de l’exécution à l’aide de la réflexion (par exemple, avec Class.getDeclaredFields() pour obtenir un tableau de Field ), mais cela peut ne pas être le cas. la meilleure solution.

Voir également

Questions connexes


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 <T> void inspect(Class<T> klazz) {
        Field[] fields = klazz.getDeclaredFields();
        System.out.printf("%d fields:%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 class String; il produit la sortie suivante:

7 fields:
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

Effective Java 2nd Edition, Article 53: Préfère les interfaces à la réflexion

Ce sont des extraits du livre:

Avec un objet Class , vous pouvez obtenir Constructor , Method , et Field instances 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 a cependant un prix:

  • Vous perdez tous les avantages de la vérification au moment de la compilation.
  • Le code requis pour effectuer un accès par réflexion est maladroit et prolixe.
  • La performance en souffre.

En règle générale, les objets ne doivent pas être accessibles de manière réfléchie dans les applications normales au moment de l'exécution.

Il existe quelques applications sophistiquées qui nécessitent une réflexion. Exemples: [... omis volontairement ...] Si vous avez des doutes sur le fait de savoir si votre application entre dans l'une de ces catégories, ce n'est probablement pas le cas.

86
polygenelubricants

Accéder directement aux champs n’est pas vraiment un bon style en Java. Je suggérerais de créer des méthodes getter et setter pour les champs de votre bean, puis d'utiliser ensuite 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);
}
39
Jörn Horstmann

Bien que je sois d’accord avec la réponse de Jörn si votre classe est conforme à la spécification JavaBeabs, voici une bonne alternative si elle ne l’est pas et si 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 de parcourir des champs de classes à l’aide d’un objet de rappel tel que:

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

        System.out.println("Field name: " + field.getName());
        field.setAccessible(true);
        System.out.println("Field value: "+ field.get(obj));

    });
}

Mais voici un avertissement: la classe est étiquetée comme "pour usage interne seulement", ce qui est dommage si vous me demandez

16
Sean Patrick Floyd

Une méthode simple pour parcourir les champs de classe et obtenir des valeurs d'objet:

 Class<?> c = obj.getClass();
 Field[] fields = c.getDeclaredFields();
 Map<String, Object> temp = new HashMap<String, Object>();

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

Java a Reflection (Java.reflection. *), Mais je suggérerais de regarder dans une bibliothèque comme Apache Beanutils, cela rendra le processus beaucoup moins complexe que d'utiliser directement la réflexion.

6
Tassos Bassoukos

Vous pouvez mettre en boucle les attributs de classe de manière dynamique à l'aide de l'API Java Reflections.

for (Field field : objClass.getDeclaredFields()) {
            // Invoke the getter method on the Institution1 object.
            Object objField = new PropertyDescriptor(field.getName(),
                    Institute1.class).getReadMethod().invoke(inst1);
2
Rehan

Voici une solution qui trie les propriétés par ordre alphabétique et les imprime toutes avec leurs valeurs:

public void logProperties() throws IllegalArgumentException, IllegalAccessException {
  Class<?> aClass = this.getClass();
  Field[] declaredFields = aClass.getDeclaredFields();
  Map<String, String> logEntries = new HashMap<>();

  for (Field field : declaredFields) {
    field.setAccessible(true);

    Object[] arguments = new Object[]{
      field.getName(),
      field.getType().getSimpleName(),
      String.valueOf(field.get(this))
    };

    String template = "- Property: {0} (Type: {1}, Value: {2})";
    String logMessage = System.getProperty("line.separator")
            + MessageFormat.format(template, arguments);

    logEntries.put(field.getName(), logMessage);
  }

  SortedSet<String> sortedLog = new TreeSet<>(logEntries.keySet());

  StringBuilder sb = new StringBuilder("Class properties:");

  Iterator<String> it = sortedLog.iterator();
  while (it.hasNext()) {
    String key = it.next();
    sb.append(logEntries.get(key));
  }

  System.out.println(sb.toString());
}
0
Benny Neugebauer