1. Obtenir des informations sur les champs
Quelle est la différence entre getFields() et getDeclaredFields()
En Java, chaque classe possède des champs (fields) — des variables déclarées à l’intérieur de la classe. Grâce à la réflexion, nous pouvons connaître leurs noms, leurs types, leurs modificateurs d’accès (public/private), ainsi que les manipuler à l’exécution. Le point d’entrée principal est l’objet Class<?>.
Méthodes principales de la classe Class pour travailler avec les champs :
| Méthode | Ce que renvoie |
|---|---|
|
Un tableau de tous les champs public de la classe, de ses parents et de ses interfaces |
|
Un tableau de tous les champs déclarés dans cette classe |
Analogie : getFields() — c’est comme une visite uniquement des salles d’exposition (public), tandis que getDeclaredFields() inclut aussi les locaux techniques (private, protected, package-private).
Exemple : afficher tous les champs de la classe
Supposons que nous ayons la classe suivante :
public class Person {
public String name;
private int age;
protected String email;
}
Récupérons des informations sur les champs :
import java.lang.reflect.Field;
Class<?> clazz = Person.class;
// Tous les champs public (y compris hérités)
System.out.println("Public fields:");
for (Field field : clazz.getFields()) {
System.out.println(field.getName() + " : " + field.getType().getSimpleName());
}
// Tous les champs déclarés (y compris private, uniquement ceux de la classe)
System.out.println("\nDeclared fields:");
for (Field field : clazz.getDeclaredFields()) {
System.out.println(field.getName() + " : " + field.getType().getSimpleName());
}
Résultat :
Public fields:
name : String
Declared fields:
name : String
age : int
email : String
Comment connaître les modificateurs d’un champ ?
Chaque champ (Field) possède des modificateurs (public/private/protected, static, final, etc.). On peut les obtenir via getModifiers() et les convertir en chaîne au moyen de Modifier :
import java.lang.reflect.Modifier;
for (Field field : clazz.getDeclaredFields()) {
int mods = field.getModifiers();
System.out.println(field.getName() + " : " + Modifier.toString(mods));
}
2. Obtenir des informations sur les méthodes
Méthodes getMethods() et getDeclaredMethods()
Les méthodes sont les actions qu’un objet peut effectuer. Grâce à la réflexion, on peut connaître les méthodes d’une classe, leurs paramètres, leurs types de retour, leurs modificateurs et leurs annotations.
| Méthode | Ce que renvoie |
|---|---|
|
Toutes les méthodes public de la classe et de ses parents (y compris Object) |
|
Toutes les méthodes déclarées dans cette classe (y compris private) |
Exemple : afficher toutes les méthodes de la classe
import java.lang.reflect.Method;
System.out.println("Public methods:");
for (Method method : clazz.getMethods()) {
System.out.println(method.getName());
}
System.out.println("\nDeclared methods:");
for (Method method : clazz.getDeclaredMethods()) {
System.out.println(method.getName());
}
Résultat (pour Person) :
Public methods:
getClass
hashCode
equals
toString
notify
notifyAll
wait
wait
wait
Declared methods:
(rien si Person n’a déclaré aucune méthode propre)
Ajoutons une méthode dans Person :
public class Person {
public String name;
private int age;
protected String email;
public void sayHello() {
System.out.println("Hi!");
}
}
À présent, getDeclaredMethods() l’affichera aussi.
Comment connaître les paramètres et le type de retour d’une méthode ?
for (Method method : clazz.getDeclaredMethods()) {
System.out.print(Modifier.toString(method.getModifiers()) + " ");
System.out.print(method.getReturnType().getSimpleName() + " ");
System.out.print(method.getName() + "(");
Class<?>[] params = method.getParameterTypes();
for (int i = 0; i < params.length; i++) {
System.out.print(params[i].getSimpleName());
if (i < params.length - 1) System.out.print(", ");
}
System.out.println(");");
}
Sortie :
public void sayHello();
3. Obtenir des informations sur les constructeurs
Les constructeurs sont des méthodes spéciales utilisées pour créer des objets.
| Méthode | Ce que renvoie |
|---|---|
|
Tous les constructeurs public |
|
Tous les constructeurs déclarés dans la classe |
Exemple : afficher tous les constructeurs de la classe
import java.lang.reflect.Constructor;
System.out.println("Constructors:");
for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
System.out.print(clazz.getSimpleName() + "(");
Class<?>[] params = constructor.getParameterTypes();
for (int i = 0; i < params.length; i++) {
System.out.print(params[i].getSimpleName());
if (i < params.length - 1) System.out.print(", ");
}
System.out.println(");");
}
Si la classe ne déclare que le constructeur par défaut, il sera affiché également.
4. Annotations : comment savoir ce qui est appliqué à une classe, une méthode ou un champ
Les annotations sont des marqueurs spéciaux que l’on peut appliquer aux classes, méthodes, champs et paramètres. Avec la réflexion, on peut savoir quelles annotations possède un élément.
Récupérer les annotations
- Pour une classe : clazz.getAnnotations()
- Pour une méthode : method.getAnnotations()
- Pour un champ : field.getAnnotations()
Exemple : vérifier la présence de l’annotation @Deprecated
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Deprecated.class)) {
System.out.println(method.getName() + " is @Deprecated");
}
}
Exemple : afficher toutes les annotations de la classe
for (var annotation : clazz.getAnnotations()) {
System.out.println(annotation);
}
5. Pratique : mini-programme pour analyser la structure d’une classe
Rassemblons tout et écrivons un petit utilitaire qui, à partir du nom d’une classe, affiche sa structure : champs, méthodes, constructeurs et annotations.
Exemple de code : ClassInspector
import java.lang.reflect.*;
import java.util.Scanner;
public class ClassInspector {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.print("Saisissez le nom complet de la classe (par exemple, java.util.ArrayList) : ");
String className = scanner.nextLine();
Class<?> clazz = Class.forName(className);
System.out.println("\n== Classe : " + clazz.getName() + " ==");
// Annotations de la classe
System.out.println("Annotations :");
for (Annotation annotation : clazz.getAnnotations()) {
System.out.println(" " + annotation);
}
// Champs
System.out.println("\nChamps :");
for (Field field : clazz.getDeclaredFields()) {
System.out.println(" " + Modifier.toString(field.getModifiers())
+ " " + field.getType().getSimpleName()
+ " " + field.getName());
}
// Méthodes
System.out.println("\nMéthodes :");
for (Method method : clazz.getDeclaredMethods()) {
System.out.print(" " + Modifier.toString(method.getModifiers())
+ " " + method.getReturnType().getSimpleName()
+ " " + method.getName() + "(");
Class<?>[] params = method.getParameterTypes();
for (int i = 0; i < params.length; i++) {
System.out.print(params[i].getSimpleName());
if (i < params.length - 1) System.out.print(", ");
}
System.out.println(");");
}
// Constructeurs
System.out.println("\nConstructeurs :");
for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
System.out.print(" " + Modifier.toString(constructor.getModifiers())
+ " " + clazz.getSimpleName() + "(");
Class<?>[] params = constructor.getParameterTypes();
for (int i = 0; i < params.length; i++) {
System.out.print(params[i].getSimpleName());
if (i < params.length - 1) System.out.print(", ");
}
System.out.println(");");
}
}
}
Comment cela fonctionne-t-il ?
- L’utilisateur saisit le nom complet de la classe (par exemple « java.util.ArrayList » ou sa propre classe).
- Le programme charge la classe dynamiquement et affiche ses annotations, champs, méthodes et constructeurs.
- Essayez avec les classes standard du JDK — vous verrez combien de choses intéressantes s’y cachent !
6. Astuces utiles et visualisation
Schéma visuel : ce que l’on peut apprendre sur une classe via la réflexion
graph TD
A[Class<?>] --> B["getFields/getDeclaredFields"]
A --> C[getMethods/getDeclaredMethods]
A --> D[getConstructors/getDeclaredConstructors]
A --> E[getAnnotations]
B --> F[Field: type, nom, modificateurs]
C --> G[Method: type de retour, paramètres]
D --> H[Constructor: paramètres]
E --> I["Annotation[]"]
Tableau : où trouver l’information
| Ce que l’on veut savoir | Comment l’obtenir via la réflexion |
|---|---|
| Tous les champs public | |
| Tous les champs déclarés | |
| Toutes les méthodes public | |
| Toutes les méthodes déclarées | |
| Tous les constructeurs public | |
| Tous les constructeurs déclarés | |
| Annotations de la classe | |
| Annotations d’une méthode/d’un champ | |
| Modificateurs | |
7. Erreurs typiques lors de l’utilisation de la réflexion
Erreur n° 1 : confondre getFields() et getDeclaredFields().
Si vous recherchez des champs private, utilisez getDeclaredFields(), et non getFields(). Le premier renvoie tous les champs déclarés dans la classe, tandis que le second — seulement les public (y compris hérités !).
Erreur n° 2 : ne pas gérer les exceptions checked.
De nombreuses méthodes de réflexion lèvent des exceptions (par exemple, ClassNotFoundException ou SecurityException). N’oubliez pas de les gérer ou de les déclarer dans la signature de la méthode.
Erreur n° 3 : ignorer les modificateurs d’accès.
L’accès aux private champs et méthodes n’est possible qu’après avoir appelé setAccessible(true), sinon une IllegalAccessException sera levée. Exemple :
Field field = clazz.getDeclaredField("age");
field.setAccessible(true); // On autorise l’accès au champ private
int value = (int) field.get(person);
Erreur n° 4 : s’attendre à ne voir que ses propres méthodes/champs.
getMethods() et getFields() renvoient les membres public non seulement de la classe courante, mais aussi de tous ses parents, y compris Object. Cela peut surprendre si vous pensiez ne voir que ce que vous avez écrit vous-même.
Erreur n° 5 : vérifier la présence d’annotations de manière incorrecte.
Utilisez isAnnotationPresent() pour vérifier une annotation précise plutôt que d’itérer manuellement le tableau des annotations sans nécessité.
GO TO FULL VERSION