Les premières méthodes exposées permettent de lire le nom de la méthode, et son modificateur.

  • getName() : retourne le nom de cette méthode.

  • getModifiers() : retourne les modificateurs de cette méthode, sous forme d'un int. Cet entier peut être décodé par les méthodes de la classe Modifier, comme nous le verrons dans le paragraphe suivant.

Viennent ensuite les méthodes qui permettent d'obtenir des informations sur le fonctionnement de cette méthode : son type de retour, les types de ses paramètres et les exceptions qu'elle jette.

  • getDeclaredAnnotations() et getAnnotations(Class) : retournent toutes les annotations posées sur cette méthode, ou l'annotation dont la classe est passée en paramètre, si elle existe.

  • getDeclaringClass() : retourne l'objet Class qui correspond à la classe qui porte cette méthode.

  • getExceptionTypes() : retourne le tableau des classes d'exception jetées par cette méthode. Si cette méthode ne jette pas d'exception, alors ce tableau est vide.

  • getReturnType() : retourne la classe du type retourné. Si ce type est un type primitif Java ( int, float, etc...), alors cette classe est une classe de type primitif ( int.class, float.class, etc...). Si ce type est void, alors la classe est void.class

  • getParameterTypes() : retourne le tableau des types des paramètres définis par cette méthode. L'ordre des paramètres est bien sûr conservé. On peut accéder aux annotations sur ces paramètres par la méthode getParameterAnnotations().

Comme nous l'avons déjà dit, il est possible d'invoquer une méthode par introspection, sur un objet donné, avec des paramètres. Cette technique est très utilisée, dans les frameworks web et ailleurs. Elle repose sur l'utilisation de la méthode invoke().

Commençons par construire une classe simple, dont nous allons invoquer les méthodes par introspection.


Nous avons juste ajouté l'affichage de messages dans le getter et dans le setter , ainsi que dans le constructeur vide. Cela va nous permettre de tracer les opérations d'invocation par introspection que nous allons faire. Utilisons maintenant ce code.

Exemple 52. Utilisation de invoke() : invocation des méthodes

// dans une méthode main
 // définition de la classe à utiliser
String className =  "org.paumard.model.Marin" ;
 // définition de la propriété utilisée
String propertyName =  "nom" ;
 // valeur de cette propriété
String value =  "Surcouf" ;

 // jette une ClassNotFoundException
 // on utilise clazz car une variable ne peut pas s'appeler class
 // création de l'objet Class à partir du nom complet de cette classe
Class<?> clazz = Class.forName(className) ;

 // jette IllegalAccessException et InstantiationException
 // instanciation de cette classe
 // invoque le constructeur vide, qui doit exister
Object o = clazz.newInstance() ;

 // construction du nom du setter, on utilise la définition classique d'un setter
StringBuilder sb =  new StringBuilder() ;
sb.append("set")
  .append(propertyName.substring(0,  1).toUpperCase())
  .append(propertyName.substring(1)) ;
String setterName = sb.toString() ;
 // interrogation de la classe pour récupérer la bonne méthode
 // jette NoSuchMethodException
Method setter = clazz.getMethod(setterName, value.getClass()) ;
 // invocation de la méthode
 // jette InvocationTargetException
setter.invoke(o, value) ;

 // affichage de l'objet, invocation de sa méthode toString()
System.out.println(o) ;

 // construction du nom du getter
sb =  new StringBuilder() ;
sb.append("get")
  .append(propertyName.substring(0,  1).toUpperCase())
  .append(propertyName.substring(1)) ;
String getterName = sb.toString() ;
 // interrogation de la classe pour récupérer la bonne méthode
Method getter = clazz.getMethod(getterName) ;

 // invocation de la méthode, récupération de l'objet retourné
Object returnedValue = getter.invoke(o) ;

 // affichage de la valeur retournée
System.out.println(returnedValue) ;

L'exécution de ce code affiche les lignes suivantes.

 Invocation du constructeur vide
 Invocation de setNom()
 Surcouf
 Invocation de getNom()
 Surcouf

Les messages successifs qui s'affichent nous montrent bien que les méthodes de la classe Marin on bien été appelées par introspection.

Il est donc possible, en Java, de fixer la valeur des propriétés d'un objet, ou de les lire, à partir du nom de la classe de cet objet, et du nom de ses propriétés. Ces noms sont des chaînes de caractères, que l'on peut lire dans des fichiers de configuration, ou des descripteurs XML. Cette propriété du langage est massivement utilisée.

Java API avancées
Retour au blog Java le soir
Cours & Tutoriaux

Table des matières

API Collection
1. Introduction
2. Interface Collection
2.1. Notion de Collection
2.2. Détail des méthodes disponibles
2.3. Interface Iterator
2.4. Implémentation, exemples d'utilisation
3. Interface List
3.1. Notion de List
3.2. Détail des méthodes disponibles
3.3. Interface ListIterator
3.4. Implémentations, exemples d'utilisation
4. Interface Set
4.1. Notion de Set
4.2. Implémentations HashSet et LinkedHashSet
4.3. Exemples d'utilisation
5. Interface SortedSet
5.1. Notion de SortedSet
5.2. Détails des méthodes disponibles
5.3. Exemples d'utilisation
6. Interface NavigableSet
6.1. Notion de NavigableSet
6.2. Détails des méthodes disponibles
6.3. Exemple d'utilisation
7. Interfaces Queue et Deque
7.1. Notion de file d'attente
7.2. Détail des méthodes disponibles
7.3. Utilisation des interfaces Queue et Deque
8. Tables de hachage
8.1. Notion de table de hachage
8.2. Interface Map
8.3. Interface Map.Entry
8.4. Interface SortedMap
8.5. Interface NavigableMap
8.6. Implémentations
8.7. Exemples d'utilisation
9. Classes utilitaires Collections et Arrays
9.1. Introduction
9.2. Classe Arrays
9.3. Classe Collections
Génériques
1. Introduction
2. Un premier exemple
2.1. Une première classe générique
2.2. Une première méthode générique
3. Contraindre un type générique
3.1. Problème posé
3.2. Contraindre un type générique
4. Implémentation des génériques
4.1. Type erasure
4.2. Types génériques et casts
4.3. Type générique et exception
4.4. Construction d'une instance générique
4.5. Génériques et membres statiques
4.6. Collisions de méthodes génériques
4.7. Implémentation de plusieurs types identiques
5. Type <?>
5.1. Introduction
5.2. Type ? extension d'un type
5.3. Type ? super-type d'un type
Expressions régulières
1. Introduction
2. Mise en œuvre des expressions régulières
2.1. Fonctionnement d'une regexp
2.2. Fonctionnement de l'API en Java
2.3. Un premier exemple
2.4. Classe Pattern
2.5. Classe Matcher
2.6. Utilisation des méthode find() et group()
2.7. Méthodes de remplacement
2.8. Sélection de régions
3. Syntaxe des expressions régulières
3.1. Notion de classe
3.2. Étude d'un cas réel
3.3. Recherche d'un mot précis
3.4. Recherche de deux mots précis
3.5. Recherche d'un mot commençant par une lettre donnée
3.6. Cas de mots comportant des caractères accentués
3.7. Recherche sur les lignes
Introspection
1. Introduction
2. La classe Class
2.1. Utilisation de Class
2.2. Méthodes disponibles
2.3. Remarque sur la propriété Accessible
2.4. Type d'une classe
2.5. Création d'une instance à partir d'un objet Class
2.6. Cas des énumérations
3. Les classes Method et Constructor
3.1. Utilisation de Method
3.2. Utilisation de Constructor
3.3. Méthodes disponibles
3.4. Invocation d'une méthode par introspection
4. La classe Field
4.1. Utilisation de Field
4.2. Méthodes disponibles
4.3. Accès à un champ par introspection
5. La classe Modifier
Programmation concurrente
1. Introduction
2. Lançons nos premiers threads
2.1. Introduction
2.2. Un premier thread, extension de Thread
2.3. Un deuxième thread, implémentation de Runnable
2.4. Remarque sur la méthode Thread.sleep(long)
2.5. Arrêter un thread
3. Concurrence d'accès
3.1. Notion d'état
3.2. Exemple de concurrence d'accès sur un état
3.3. Analyse de la concurrence d'accès
3.4. Solution au problème
3.5. Champs volatile
4. Synchronisation
4.1. Définition d'un bloc synchronisé
4.2. Fonctionnement d'un bloc synchronisé
4.3. Notion de deadlock
4.4. Bonnes pratiques pour la synchronisation de threads
5. Opérations atomiques
5.1. Atomicité d'une opération
5.2. Solutions disponibles
5.3. Variables atomiques
6. Collections synchronisées et concurrentes
6.1. Introduction
6.2. Position du problème
6.3. Solutions proposées
7. Files d'attente
7.1. Introduction, pattern producteur / consommateur
7.2. Interface BlockingQueue<E>
7.3. Implémentations de BlockingQueue
7.4. Exemple de producteur / consommateur
7.5. Arrêter un producteur / consommateur : pilule empoisonnée
8. Classes utilitaires de l'API Concurrent
8.1. Introduction
8.2. Énumération TimeUnit
8.3. Interface Callable<V>
8.4. Interfaces Future<V> et RunnableFuture<V>
8.5. Interface ScheduledFuture<V> et RunnableScheduledFuture<V>
9. Pattern executor
9.1. Notion de réserve de threads
9.2. Interface Executor
9.3. Interface ExecutorService
9.4. Interface ScheduledExecutorService
9.5. Classe Executors
9.6. Pattern de lancement de tâches
10. Classes de contrôle d'accès
10.1. Introduction
10.2. Interfaces Lock et ReadWriteLock
10.3. Notion de verrou réentrant
10.4. Classe RentrantLock
10.5. Classe ReadWriteRentrantLock
11. Sémaphores, barrières et latches
11.1. Introduction
11.2. Notion de sémaphore, classe Semaphore
11.3. Notion de latch, classe CountDownLatch
11.4. Notion de barrière, classe CyclicBarrier