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?
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.
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
Ce sont des extraits du livre:
Avec un objet
Class
, vous pouvez obtenirConstructor
,Method
, etField
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.
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);
}
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
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) {
}
}
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.
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);
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());
}