Method
, comme son nom le laisse supposer, permet de modéliser les méthodes d'une classe ou d'une interface, concrètes ou abstraites.
La façon la plus simple d'obtenir une référence sur une méthode, est d'utiliser une des méthodes
getMethod()
de la classe
Class
. Dans certains cas, on peut aussi recevoir une méthode en paramètre d'un
callback
.
La classe
Method
fonctionne sur le même principe que la classe
Class
. Elle permet d'obtenir toutes les informations sur cette méthode :
Constructor
modélise les constructeurs d'une classe. Dans la mesure où un constructeur n'est pas une méthode, il est logique d'avoir deux classes différentes pour modéliser ces deux notions. Cela dit, les méthodes exposées et le fonctionnement de ces deux classes sont quasiment les mêmes.
On obtient une instance de
Constructor
par invocation de l'une des méthodes
getConstructor()
de la classe
Class
.
Alors que la classe
Method
expose une méthode
invoke()
pour être invoquée par introspection, la classe
Constructor
expose une méthode
newInstance()
, qui prend en paramètre les paramètres à passer au constructeur modélisé par cet objet.
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.
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()
.
invoke()
.
Commençons par construire une classe simple, dont nous allons invoquer les méthodes par introspection.
Exemple 51. Utilisation de
invoke()
: classe de test
public class Marin { private String nom ; // constructeur vide standard public Marin() { System.out.println("Invocation du constructeur vide") ; } // setter standard public void setNom(String nom) { System.out.println("Invocation de setNom()") ; this.nom = nom ; } // getter standard public String getNom() { System.out.println("Invocation de setNom()") ; return this.nom ; } // méthode toString() standard public String toString() { // utilisation d'un StringBuffer StringBuffer sb = new StringBuffer() ; sb.append(nom) ; return sb.toString() ; } }
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) ;
Invocation du constructeur vide Invocation de setNom() Surcouf Invocation de getNom() SurcoufLes 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.