Comment faire une boucle sur les attributs D'une classe en Java?
Comment puis-je faire une boucle sur les attributs d'une classe en java dynamiquement.
Pour 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?
7 réponses
Il n'y a pas de support linguistique pour faire ce que vous demandez.
Vous pouvez accéder de manière réflective aux membres d'un type au moment de l'exécution en utilisant la réflexion (par exemple avec Class.getDeclaredFields()
pour obtenir un tableau de Field
), mais selon ce que vous essayez de faire, cela peut ne pas être la meilleure solution.
Voir aussi
Connexes questions
- qu'est-Ce que la réflexion, et pourquoi est-il utile?
- réflexion Java: Pourquoi est - ce si mauvais?
- Comment la réflexion pourrait-elle ne pas conduire à des odeurs de code?
- vider les propriétés d'un objet java
Exemple
Voici un exemple simple pour montrer seulement une partie de ce que reflection 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érer les interfaces à la réflexion
Ce sont des extraits du livre:
Donné un
Class
objet, vous pouvez obtenirConstructor
,Method
, etField
les instances représentant les constructeurs, les méthodes et les champs de la classe. [Ils] vous permettent de manipuler leurs homologues sous-jacents de manière réflective . Ce pouvoir, cependant, vient à un prix:
- vous perdez tous les avantages de la vérification à la compilation.
- le code requis pour effectuer un accès réfléchissant est maladroit et verbeux.
- la Performance en souffre.
En règle générale, les objets ne doivent pas être accessibles de manière réflective dans les applications normales au moment de l'exécution.
Il y a quelques applications sophistiquées qui nécessitent une réflexion. Les exemples incluent [...omis à dessein...] Si vous avez des doutes quant à savoir si votre l'application tombe dans l'une de ces catégories, ce n'est probablement pas le cas.
Accéder directement aux champs n'est pas vraiment un bon style en java. Je suggère de créer des méthodes getter et setter pour les champs de votre bean, puis d'utiliser ensuite les classes Introspector et BeanInfo de java.haricots paquet.
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);
}
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 ce n'est pas le cas et que vous utilisez Spring.
Spring a une classe nommée ReflectionUtils {[3] } qui offre des fonctionnalités très puissantes, y compris doWithFields (class, callback) , une méthode de style visiteur qui vous permet d'itérer sur un champs de classes en utilisant un objet de rappel comme ceci:
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 interne utiliser uniquement", ce qui est dommage si vous me demandez
Moyen Simple d'itérer sur les champs de classe et d'obtenir des valeurs à partir de l'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) {
}
}
Java a une réflexion (java.réflexion.* ), mais je suggère de regarder dans une bibliothèque comme Apache Beanutils, cela rendra le processus beaucoup moins Poilu que d'utiliser la réflexion directement.
Vous pouvez boucler les attributs de classe dynamiquement en utilisant java Reflections API -
for (Field field : objClass.getDeclaredFields()) {
// Invoke the getter method on the Institution1 object.
Object objField = new PropertyDescriptor(field.getName(),
Institute1.class).getReadMethod().invoke(inst1);
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());
}