Java et la réflexivité
Voici un chapitre qui, je pense, ne vous servira pas tout de
suite.
Cependant, il me semble important d'en parler...
La réflexivité n'est en fait que le moyen de connaître toutes les informations concernant une classe donnée. Vous pourrez même créer des instances de classe de façon dynamique grâce à ceci.
Je pense faire une partie sur les design pattern après celle sur les interfaces graphiques ! Et, à ce moment, vous aurez sans doute besoin des connaissances de ce chapitre, surtout lorsque nous aborderons le pattern factory.
En attendant, je pense que ce chapitre va tout de même vous intéresser !
Alors, allons-y...
Cependant, il me semble important d'en parler...
La réflexivité n'est en fait que le moyen de connaître toutes les informations concernant une classe donnée. Vous pourrez même créer des instances de classe de façon dynamique grâce à ceci.
Je pense faire une partie sur les design pattern après celle sur les interfaces graphiques ! Et, à ce moment, vous aurez sans doute besoin des connaissances de ce chapitre, surtout lorsque nous aborderons le pattern factory.
En attendant, je pense que ce chapitre va tout de même vous intéresser !
Alors, allons-y...
Sommaire du chapitre :
- Commençons par le commencement
- Interroger un objet Class
- Instanciation dynamique
- Ce qu'il faut retenir
Commençons par le commencement
La réflexivité, aussi appelée introspection, consiste à découvrir de façon
dynamique des informations propres à une classe Java ou à un objet. Ceci est
notamment utilisé au niveau de la machine virtuelle Java lors de l'exécution de
votre programme. En gros, votre machine virtuelle stocke les informations
relatives à une classe dans un objet.
Concrètement, que se passe-t-il ?
Au chargement d'une classe Java, votre JVM crée automatiquement un objet. Celui-ci récupère toutes les caractéristiques de votre classe ! Il s'agit d'un objet Class.
Exemple: si vous avez créé trois nouvelles classes Java, à l'exécution de votre programme, la JVM va créer un objet Class pour chacune d'elles.
Comme vous devez vous en douter, cet objet possède une multitude de méthodes qui permettent d'avoir tous les renseignements possibles et imaginables sur une classe.
Dans ce chapitre, nous allons visiter la classe String.
Créez un nouveau projet ainsi qu'une classe contenant la méthode main.
Voici deux façons de récupérer un objet Class :
Code : Java -
1 2 3 4 5 6 7 8 9 10 11 |
public class Test {
public static void main(String[] args) {
Class c = String.class;
Class c2 = new String().getClass();
/*La fameuse méthode finale dont je vous parlais dans le chapitre sur l'héritage Cette méthode vient de la classe Object
*/
}
}
|
Maintenant que vous savez récupérer un objet Class, nous allons tout de suite voir ce qu'il sait faire !
Interroger un objet Class
Dans ce sous-chapitre, nous
allons voir une partie des choses que sait faire un objet Class.
Je ne vais pas tout vous montrer... De toute façon, je pense que vous êtes à
même de chercher et de trouver tous seul maintenant. Vous avez l'habitude de
manipuler des objets, à présent...
Connaître la super classe d'une classe
Ce qui nous donne :
La classe Object n'a pas de super-classe...
Voyez plutôt :
Connaître la liste des interfaces
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class Test {
public static void main(String[] args) {
//On récupère un objet Class
Class c = new String().getClass();
//La méthode getInterfaces retourne un tableau de Class Class[] faces = c.getInterfaces(); //Pour voir le nombre d'interfaces
System.out.println("Il y a " + faces.length + " interfaces implémentées"); //On parcourt le tableau d'interfaces for(int i = 0; i < faces.length; i++)
System.out.println(faces[i]);
} }
|
Ce qui nous donne :
Connaître la liste des méthodes de la classe
La méthode getMethods() de l'objet Class nous retourne un tableau d'objets Method présents dans le package java.lang.reflect.
Vous pouvez soit faire l'import à la main, soit déclarer un tableau d'objets Method et utiliser le raccourci Ctrl + Shift + O.
Voici un code qui retourne la liste des méthodes de la classe String :
Code : Java -
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
Class c = new String().getClass();
Method[] m = c.getMethods(); System.out.println("Il y a " + m.length + " méthodes dans cette classe"); //On parcourt le tableau de méthodes
for(int i = 0; i < m.length; i++) System.out.println(m[i]);
} }
|
Voici un morceau du résultat car, comme vous pourrez le voir, il y a beaucoup de méthodes dans la classe String.
Vous pouvez constater que l'objet Method regorge lui aussi de méthodes intéressantes. Voici un code qui affiche la liste des méthodes ainsi que la liste des attributs qu'elles prennent :
Code : Java -
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
Class c = new String().getClass();
Method[] m = c.getMethods(); System.out.println("Il y a " + m.length + " méthodes dans cette classe"); //On parcourt le tableau de méthodes
for(int i = 0; i < m.length; i++) {
System.out.println(m[i]);
Class[] p = m[i].getParameterTypes();
for(int j = 0; j < p.length; j++)
System.out.println(p[j].getName());
System.out.println("----------------------------------------\n"); }
}
}
|
Et voilà :
Connaître la liste des champs (variable de classe ou d'instance) de la classe
Ici, nous allons appliquer la même méthodologie que pour la liste des méthodes sauf que cette fois, la méthode invoquée retourne un tableau d'objets Field. Voici un code qui affiche la liste des champs de la classe String.
Code : Java -
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) {
Class c = new String().getClass();
Field[] m = c.getFields(); System.out.println("Il y a " + m.length + " champs dans cette classe"); //On parcourt le tableau de méthodes
for(int i = 0; i < m.length; i++) System.out.println(m[i].getName());
} }
|
Connaître la liste des constructeurs de la classe
Ici, nous utiliserons un objet Constructor pour lister les constructeurs de la classe :
Code : Java -
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import java.lang.reflect.Constructor; public class Test {
public static void main(String[] args) {
Class c = new String().getClass();
Constructor[] construc = c.getConstructors(); System.out.println("Il y a " + construc.length + " constructeurs dans cette classe"); //On parcourt le tableau des constructeur
for(int i = 0; i < construc.length; i++){ System.out.println(construc[i].getName());
Class[] param = construc[i].getParameterTypes();
for(int j = 0; j < param.length; j++)
System.out.println(param[j]);
System.out.println("------------------------------------\n"); }
}
}
|
Vous pouvez donc constater que l'objet Class regorge de méthodes en tout genre !
Maintenant, si nous essayons d'exploiter un peu plus celles-ci...
Instanciation dynamique
Nous allons voir une petite
partie de la puissance de cette classe (pour l'instant).
Dans un premier temps, créez un nouveau projet avec une méthode main, ainsi qu'une classe correspondant à ceci :
Dans un premier temps, créez un nouveau projet avec une méthode main, ainsi qu'une classe correspondant à ceci :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
public class Paire { private String valeur1, valeur2; public Paire(){ this.valeur1 = null; this.valeur2 = null;
System.out.println("Instanciation ! !");
}
public Paire(String val1, String val2){
this.valeur1 = val1; this.valeur2 = val2; System.out.println("Instanciation avec des paramètres ! !"); }
public String toString(){ return "Je suis un objet qui a pour valeur : " + this.valeur1 + " - " + this.valeur2; }
public String getValeur1() {
return valeur1;
} public void setValeur1(String valeur1) { this.valeur1 = valeur1; }
public String getValeur2() {
return valeur2;
} public void setValeur2(String valeur2) { this.valeur2 = valeur2; }
}
|
Le but du jeu maintenant consiste à créer un objet Paire sans utiliser l'opérateur new.
Pour instancier un nouvel objet Paire, nous allons tout d'abord récupérer ses constructeurs. Ensuite, nous allons préparer un tableau contenant les données à insérer. Puis nous invoquerons la méthode toString().
Regardez comment procéder ; par contre, il y a moultes exceptions :
Code : Java -
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException;
public class Test {
public static void main(String[] args) {
String nom = Paire.class.getName();
try { //On crée un objet Class
Class cl = Class.forName(nom); //Nouvelle instance de la classe Paire Object o = cl.newInstance(); //On crée les paramètres du constructeur
Class[] types = new Class[]{String.class, String.class}; //On récupère le constructeur avec les deux paramètres Constructor ct = cl.getConstructor(types); //On instancie l'objet avec le constructeur surchargé ! Object o2 = ct.newInstance(new String[]{"valeur 1 ", "valeur 2"} );
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
}
|
Et le résultat donne :
Nous pouvons maintenant appeler la méthode toString()
du deuxième objet... oh et soyons fous, sur les deux :
Code : Java -
Code : Java -
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
String nom = Paire.class.getName();
try { //On crée un objet Class
Class cl = Class.forName(nom); //Nouvelle instance de la classe Paire Object o = cl.newInstance(); //On crée les paramètres du constructeur
Class[] types = new Class[]{String.class, String.class}; //On récupère le constructeur avec les deux paramètres Constructor ct = cl.getConstructor(types); //On instancie l'objet avec le constructeur surchargé ! Object o2 = ct.newInstance(new String[]{"valeur 1 ", "valeur 2"} ); //On va chercher la méthode toString, elle n'a aucun paramètre
Method m = cl.getMethod("toString", null); //La méthode invoke exécute la méthode sur l'objet passé en paramètre, // pas de paramètre, donc null en deuxième paramètre de la méthode invoke !
System.out.println("---------------------------------------------"); System.out.println("Méthode " + m.getName() + " sur o2: " +m.invoke(o2, null)); System.out.println("Méthode " + m.getName() + " sur o: " +m.invoke(o, null)); } catch (SecurityException e) { // TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace(); }
}
}
|
Et le résultat:
Voilà : nous venons de créer deux instances d'une classe sans passer par l'opérateur new. Mieux encore ! Car nous avons même pu appeler une méthode de nos instances !
Je ne vais pas m'attarder trop longtemps sur ce sujet... Mais gardez en tête que cette façon de faire, même si elle est très lourde, pourrait vous être utile. Et là, je repense à mon pattern factory. En quelques mots, il s'agit d'une classe Java qui ne fait que créer des instances !
Bon. Je crois que vous avez bien mérité une pause. Les deux derniers chapitres ont été assez éprouvants...
Un petit topo et en route pour la partie 3 !
Ce qu'il faut retenir
- Lorsque votre JVM interprète votre programme, elle crée automatiquement un objet Class pour chaque classe chargée.
- Avec un tel objet, vous pouvez connaître absolument tout sur votre classe.
- L'objet Class utilise des sous-objets comme Method, Field, Constructor... qui permettent de travailler avec vos différents objets, mais aussi avec ceux présents dans Java.
- Avec cet objet, vous pouvez créer des instances de vos classes Java sans utiliser new.
- Par contre, vous devez savoir que les performances restent médiocres.
Voilà, c'était le dernier chapitre de cette partie !
Il y a eu pas mal de choses vues ici...
Je ne vais faire de long discours maintenant que vous êtes si près de la programmation événementielle...
Alors... Rendez-vous dans la troisième partie.
Il y a eu pas mal de choses vues ici...
Je ne vais faire de long discours maintenant que vous êtes si près de la programmation événementielle...
Alors... Rendez-vous dans la troisième partie.
// //
0
comments
//
0 comments to "LECON 209"
Post a Comment