Corrigé - Département Informatique
Transcription
Corrigé - Département Informatique
UNIVERSITÉ DE NICE – SOPHIA ANTIPOLIS Master d’informatique 1ère année UFR FACULTÉ DES SCIENCES Génie logiciel orienté objet 2006-2007 Parc Valrose – BP 71 – F 06108 NICE Cedex 2 P. Collet, R. Rousseau Séance de TP n◦ 02 de la semaine du 10 octobre 2006 Réflexivité en Java Corrigé Exercice 1 : un analyseur de classes Ecrivez une programme qui attend qu’on tape au clavier le nom d’une classe puis qui affiche à l’écran, si possible avec une indentation significative, toutes les informations relatives à cette classe. On ne demande que les membres définis dans la classe,x pas ceux qui sont hérités. Voici “un exemple d’utilisation” avec la classe Date : Classe non générique analysée en utilisant les primitives du JDK 1.4 Entrez le nom d’une classe (ex : java.util.Date): java.util.Date public class java.util.Date implements java.io.Serializable, java.lang.Cloneable, java.lang.Comparable { private private private private private private private private static final sun.util.calendar.BaseCalendar gcal; static sun.util.calendar.BaseCalendar jcal; transient long fastTime; transient sun.util.calendar.BaseCalendar$Date cdate; static int defaultCenturyStart; static final long serialVersionUID; static final [Ljava.lang.String; wtb; static final [I ttb; public public public public public public java.util.Date(int, int, int, int, int, int){} java.util.Date(java.lang.String){} java.util.Date(int, int, int, int, int){} java.util.Date(int, int, int){} java.util.Date(long){} java.util.Date(){} public public public public public public public public public public public public public public int hashCode(){} int compareTo(java.util.Date){} volatile int compareTo(java.lang.Object){} java.lang.Object clone(){} boolean equals(java.lang.Object){} java.lang.String toString(){} static long parse(java.lang.String){} boolean after(java.util.Date){} boolean before(java.util.Date){} int getDate(){} int getHours(){} int getMinutes(){} int getMonth(){} int getSeconds(){} Séance de TP n◦ 02– Réflexivité en Java public public public public public public public public public public public public public public public public public public public public 2 long getTime(){} int getYear(){} void setTime(long){} static long UTC(int, int, int, int, int, int){} int getDay(){} int getTimezoneOffset(){} void setDate(int){} void setHours(int){} void setMinutes(int){} void setMonth(int){} void setSeconds(int){} void setYear(int){} java.lang.String toGMTString(){} java.lang.String toLocaleString(){} final native java.lang.Class getClass(){} final void wait() throws java.lang.InterruptedException{} final void wait(long, int) throws java.lang.InterruptedException{} final native void wait(long) throws java.lang.InterruptedException{} final native void notify(){} final native void notifyAll(){} } Classe générique analysée en utilisant les primitives de Java 5 public class java.util.HashMap <K, V> extends java.util.AbstractMap <K, V> implements java.util.Map <K, V>, java.lang.Cloneable, java.io.Serializable { static final int DEFAULT_INITIAL_CAPACITY; static final int MAXIMUM_CAPACITY; static final float DEFAULT_LOAD_FACTOR; transient [Ljava.util.HashMap$Entry; table; transient int size; int threshold; final float loadFactor; transient volatile int modCount; static final java.lang.Object NULL_KEY; private static final boolean useNewHash; private transient java.util.Set <E> entrySet; private static final long serialVersionUID; public public public public java.util.HashMap java.util.HashMap java.util.HashMap java.util.HashMap public public public public public public public public public public public public public java.lang.Object put(java.lang.Object, java.lang.Object){} java.lang.Object clone(){} void clear(){} java.util.Set <E> entrySet(){} java.lang.Object get(java.lang.Object){} void putAll(java.util.Map <K, V>){} int size(){} java.util.Collection <E> values(){} java.lang.Object remove(java.lang.Object){} boolean containsKey(java.lang.Object){} boolean containsValue(java.lang.Object){} boolean isEmpty(){} java.util.Set <E> keySet(){} <K, <K, <K, <K, V>(){} V>(java.util.Map <K, V>){} V>(int, float){} V>(int){} Séance de TP n◦ 02– Réflexivité en Java public public public public public public public public public 3 int hashCode(){} boolean equals(java.lang.Object){} java.lang.String toString(){} final native java.lang.Class <T> getClass(){} final void wait() throws java.lang.InterruptedException{} final void wait(long, int) throws java.lang.InterruptedException{} final native void wait(long) throws java.lang.InterruptedException{} final native void notify(){} final native void notifyAll(){} } Voici un squelette de la classe “AnalyseurDeClasse.java”. 2 /∗ ∗ 3 4 5 6 7 ∗ @version 1.00 23 Mars 2001 ∗ @author Michel Buffa ∗ Inspiré par la classe Reflectiontest . java de ∗ Cay S. Horstmann & Gary Cornell , publiée dans le livre ∗/ 10 import java.lang.reflect.*; import java.io.*; 12 public class AnalyseurDeClasse { 9 14 Core Java , Sun Press public static void analyseClasse(String nomClasse) throws ClassNotFoundException { 15 // Récupération 16 Class cl = getClasse(nomClasse); 18 afficheEnTeteClasse(cl); 20 System.out.println(); afficheAttributs(cl); 21 d’ un objet de type Class correspondant au nom passé en paramètres System.out.println(); afficheConstructeurs(cl); 23 24 System.out.println(); afficheMethodes(cl); 26 27 29 // L’ accolade fermante 30 System.out.println("}"); de fin de classe ! 31 } 34 /∗ ∗ Retourne la classe 35 public static Class getClasse(String nomClasse) throws ClassNotFoundException { // CODE A ECRIRE 36 37 dont le nom est passé en paramètre ∗/ } 39 /∗ ∗ Cette méthode affiche 40 public static void afficheEnTeteClasse(Class cl) { 41 42 44 45 // Affichage du modifier // CODE A ECRIRE // Récupération par ex "public class Toto extends Tata implements Titi , Tutu {" ∗/ et du nom de la classe de la superclasse si elle Class supercl = // CODE A ECRIRE existe ( null si cl est le type Object ) Séance de TP n◦ 02– Réflexivité en Java 4 // On ecrit le "extends " que si la superclasse // différente de Object // CODE A ECRIRE 47 48 49 // Affichage des interfaces // CODE A ECRIRE 51 52 que la classe 54 // Enfin , l ’ accolade ouvrante 55 System.out.print(" {\n"); est non nulle implemente ! 56 } 58 public static void afficheAttributs(Class cl) { // CODE A ECRIRE 59 60 } 62 public static void afficheConstructeurs(Class cl) { // CODE A ECRIRE 63 System.out.println("{}"); 64 } 65 public static void afficheMethodes(Class cl) { 68 69 // CODE A ECRIRE 70 System.out.println("{}"); } 71 public static String litChaineAuClavier() throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); return br.readLine(); } 73 74 75 76 public static void main(String[] args) { boolean ok = false; 78 79 while(!ok) { try { System.out.print("Entrez le nom d’une classe (ex : java.util.Date): "); String nomClasse = litChaineAuClavier(); 81 82 83 84 analyseClasse(nomClasse); 86 ok = true; } catch(ClassNotFoundException e) { System.out.println("Classe non trouvée."); }catch(IOException e) { System.out.println("Erreur d’E/S!"); } 88 89 90 91 92 93 } 94 } 95 97 et } Vous devez compléter le code. N’oubliez de travailler de manière incrémentale (d’abord au moins le nom de la classe, puis les classes ancêtres, etc). Remarque: Pour commencer, ne vous occupez pas de la généricité : partout ou vous manipulerez un objet de type "Class", vous l’afficherez simplement par son nom en utilisant la méthode getName. Corrigé ⇒ Séance de TP n◦ 02– Réflexivité en Java 5 On obtient les classes suivantes. Classe AnalyseurDeClasse.java 1 /∗ ∗ 2 3 4 5 6 8 9 10 12 13 14 16 ∗ @version 1.00 23 Mars 2001 ∗ @author Michel Buffa ∗ Inspiré par la classe Reflectiontest . java de ∗ Cay S. Horstmann & Gary Cornell , publiée dans le livre ∗/ Core Java , Sun Press import java.lang.reflect.*; import java.io.*; import javax.swing.*; public class AnalyseurDeClasse { JPanel jPanel1 = new JPanel(); JButton jButton1 = new JButton(); public static void analyseClasse(String nomClasse) throws ClassNotFoundException { 17 // Récupération 18 Class cl = Class.forName(nomClasse); 20 afficheEnTeteClasse(cl); 22 System.out.println(); afficheAttributs(cl); 23 d’ un objet de type Class correspondant au nom passé en paramètres System.out.println(); afficheConstructeurs(cl); 25 26 System.out.println(); afficheMethodes(cl); 28 29 31 // L’ accolade fermante 32 System.out.println("}"); de fin de classe ! 33 } 35 public static void afficheEnTeteClasse(Class cl) { 36 // 37 System.out.print(Modifier.toString(cl.getModifiers())); System.out.print(" class " + cl.getName()); 38 40 Affichage // Récupération du modifier , du nom de la classe de la superclasse si elle existe et son entête si elle ( null si cl est le type Object ) 41 Class supercl = cl.getSuperclass(); 43 44 // On ecrit le "extends " que si la superclasse // différente de Object 45 if (supercl != null && !supercl.equals(Object.class)) 46 47 48 est non nulle // ou variante suivante : // if ( supercl != null && supercl . getSuperclass () != null ) 50 // Affichage 51 Class[] interfaces = cl.getInterfaces(); if (interfaces.length != 0) { System.out.print(" implements "); for(int i = 0; i < interfaces.length; i++) { System.out.print(interfaces[i].getName()); if (i != (interfaces.length -1)) { System.out.print(", "); 52 53 54 55 56 57 et System.out.print(" extends " + supercl.getName()); des interfaces que la classe est générique implemente Séance de TP n◦ 02– Réflexivité en Java 6 } 58 } 59 } 60 61 // Enfin , l ’ accolade ouvrante 62 System.out.print(" {\n"); ! 63 } 65 public static void afficheAttributs(Class cl) { Field[] fields = cl.getDeclaredFields(); 66 for (int i = 0; i < fields.length; i++){ 68 69 // Le ième attribut 70 Field f = fields[i]; 71 // Le type du ième attribut 72 Class type = f.getType(); 73 // Son nom sous forme de chaîne de caractère 74 String name = f.getName(); 76 // On écrit 77 System.out.print("\t" + Modifier.toString(f.getModifiers())); d’ abord son modifier 78 // Puis son type et son nom ! 79 System.out.println(" " + type.getName() + " " + name + ";"); } 80 81 } 83 public static void afficheConstructeurs(Class cl) { Constructor[] constructors = cl.getDeclaredConstructors(); 84 for (int i = 0; i < constructors.length; i++) { 86 87 // Le ième constructeur 88 Constructor c = constructors[i]; 90 // Affichage 91 92 System.out.print("\t" + Modifier.toString(c.getModifiers())); System.out.print(" " + cl.getName() + "("); du modifier + du nom de la classe ( eq. nom du constructeur 94 // Affichage du type des paramètres 96 // Le type des 97 102 Class[] paramTypes = c.getParameterTypes(); for (int j = 0; j < paramTypes.length; j++) { if (j > 0) System.out.print(", "); System.out.print(paramTypes[j].getName()); } System.out.print(")"); 104 // Affichage 105 Class[] exceptions = c.getExceptionTypes(); if (exceptions.length != 0) { System.out.print(" throws "); for(int k = 0; k < exceptions.length; k++) { System.out.print(exceptions[k]); if (k != (exceptions.length -1)) { System.out.print(", "); } } } System.out.println("{}"); 98 99 100 101 106 107 108 109 110 111 112 113 114 115 paramètres est un tableau d’ objet Class des Exceptions } 117 118 } 120 public static void afficheMethodes(Class cl) { Method[] methods = cl.getMethods(); 121 ) Séance de TP n◦ 02– Réflexivité en Java 7 for (int i = 0; i < methods.length; i++) { 123 124 // La ième méthode 125 Method m = methods[i]; 126 // Le type de retour 127 Class retType = m.getReturnType(); 128 // Le tableau 129 Class[] paramTypes = m.getParameterTypes(); des types des paramètres 130 // Le nom de la méthode 131 String name = m.getName(); 133 // Affichage 134 135 System.out.print("\t" + Modifier.toString(m.getModifiers())); System.out.print(" " + retType.getName() + " " + name); 137 // Affichage 138 143 System.out.print("("); for (int j = 0; j < paramTypes.length; j++) { if (j > 0) System.out.print(", "); System.out.print(paramTypes[j].getName()); } System.out.print(")"); 145 // Affichage 146 Class[] exceptions = m.getExceptionTypes(); if (exceptions.length != 0) { System.out.print(" throws "); for(int k = 0; k < exceptions.length; k++) { System.out.print(exceptions[k].getName()); if (k != (exceptions.length -1)) { System.out.print(", "); } } } System.out.println("{}"); 139 140 141 142 147 148 149 150 151 152 153 154 155 156 du modifier + type de retour + nom de la méthode des types des paramètres des Exceptions } 157 158 } 160 public static String litChaineAuClavier() throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); return br.readLine(); } 161 162 163 165 166 public static void main(String[] args) { boolean ok = false; while(!ok) { try { System.out.print("Entrez le nom d’une classe (ex : java.util.Date): "); String nomClasse = litChaineAuClavier(); 168 169 170 171 analyseClasse(nomClasse); 173 ok = true; } catch(ClassNotFoundException e) { System.out.println("Classe non trouvée."); }catch(IOException e) { System.out.println("Erreur d’E/S!"); } 175 176 177 178 179 180 } 181 182 } Séance de TP n◦ 02– Réflexivité en Java public AnalyseurDeClasse() { try { jbInit(); } catch(Exception e) { e.printStackTrace(); } } private void jbInit() throws Exception { jButton1.setText("jButton1"); jPanel1.add(jButton1, null); } 184 185 186 187 188 189 190 191 192 193 194 195 196 8 } Classe Methodes 2 /∗ ∗ 3 4 5 7 8 ∗ Trouver toutes les méthodes d’ une classe , ∗ y compris celles qui sont héritées . ∗/ import java.lang.reflect.*; import java.util.*; 10 /∗ ∗ 11 12 13 14 15 16 17 18 19 ∗ Affiche les méthodes d’ une classe . ∗ @param class la classe dont on veut les méthodes . ∗ @param visionPaquetage vrai si on veut retenir les méthodes "package " ∗ des classes ancêtre qui sont dans le même paquetage que class . ∗ C’est −à−dire, on veut les méthodes de class visible du même ∗ paquetage . ∗/ public class Methodes { public static void printMethods(Class cl, boolean visionPaquetage) { 20 // Vrai si on affiche 21 boolean retenirPaquetage = false; les méthodes d’ accès "package " 22 // Paquetage de la classe 23 Package paquetage = cl.getPackage(); 25 /∗ Si on examine une classe classes private . ∗/ 26 27 28 ( pour le comparer à celui ancêtre , on ne retient des classes mères ) pas les boolean ancetre = false; // vrai si on examine une classe ancêtre HashSet methodes = new HashSet(); 29 // On remonte les classes 30 while (cl != null) { System.out.println("Classe " + cl.getName() + "------------"); 31 ancêtres jusqu ’ à Object . // Les méthodes qui sont déclarées // ( pas héritées ) . 34 Method[] methods = cl.getDeclaredMethods(); 35 // Est −ce que la classe est dans le même paquetage // que la classe de départ ? 36 dans la classe elle −même 33 32 37 retenirPaquetage = (paquetage == cl.getPackage()) && visionPaquetage; 39 for (int i = 0; i < methods.length; i++) { Method m = methods[i]; int modifieurs = m.getModifiers(); 40 41 Séance de TP n◦ 02– Réflexivité en Java // Cas où on ne doit pas retenir la méthode : // elle est private , ou "package " et on ne retient // pas les méthodes "package ". 42 43 44 if (ancetre && (Modifier.isPrivate(modifieurs) || ((!Modifier.isPublic(modifieurs)) && (!Modifier.isProtected(modifieurs)) && !retenirPaquetage))) { continue; } 45 46 47 48 49 50 51 Class[] paramTypes = m.getParameterTypes(); String nomMethode = m.getName(); 53 54 55 // System . out . println (" Nom de la méthode : " + nomMethode); 56 Class retType = m.getReturnType(); String nomTypeRetour; if (retType == null) { nomTypeRetour = "void"; } else { nomTypeRetour = retType.getName(); } Methode methode = new Methode(modifieurs, nomMethode, paramTypes, nomTypeRetour, cl.getName()); if (! methodes.add(methode)) { 57 58 59 60 61 62 63 64 65 66 67 // System . out . println (" Déjà dans le set : " + methode ) ; 68 continue; 69 } 70 71 // On garde la méthode 72 System.out.println(methode); } cl = cl.getSuperclass(); ancetre = true; 73 74 75 } 76 // System . out . println ( methodes ) ; 77 78 } 80 // Juste 81 private int[][] machin(Boolean[] truc) { return null; } 82 83 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 pour tester les noms de tableaux /∗ ∗ ∗ Un profil de méthode . ∗ ∗ Sert pour savoir si une méthode d’ une classe ancêtre ∗ doit être affichée ou non. ∗ L’ idée est de ranger les méthodes dans un Set en s ’ arrangeant ∗ pour que les méthodes de même signature soient égales . ∗ D’après les propriétés des Set , un objet n’ est pas rangé ∗ dans un Set si celui −ci contient déjà un objet égal au sens de equals . ∗ Attention ! ne pas oublier de redéfinir la méthode hashcode dans la ∗ classe Methode, et elle doit être compatible avec equals . ∗ Si on commence par les méthodes de la classe pour remonter ∗ dans les classes mères jusqu ’ à Object , on ne rangera donc pas ∗ les méthodes qui ont été redéfinies dans une des classes ∗ filles ( car elles auront même signature qu’ une méthode déjà ∗ rencontrée ) . ∗ ∗/ private static class Methode { private int modifieurs; private String nom; 9 Séance de TP n◦ 02– Réflexivité en Java 10 private String paramTypes; private String returnType; private String classeDefinition; 106 107 108 /∗ ∗ ∗ @param modifieurs modificateurs de la méthode . ∗ @param nom nom de la méthode . ∗ @param paramTypes types des paramètres de la méthode . ∗ @param returnType type retour de la méthode . ∗ @param classeDefinition classe dans laquelle cette méthode ∗ a été définie . ∗/ 110 111 112 113 114 115 116 117 132 private Methode(int modifieurs, String nom, Class[] paramTypes, String returnType, String classeDefinition ) { this .modifieurs = modifieurs; this .nom = nom; this .paramTypes = ""; if (paramTypes.length > 0) { for (int i = 0; i < paramTypes.length - 1; i++) { this .paramTypes += transform(paramTypes[i].getName()) + ", "; } this .paramTypes += transform(paramTypes[paramTypes.length - 1].getName()); } this .returnType = returnType; this .classeDefinition = classeDefinition; } 134 public boolean equals(Object objet) { 118 119 120 121 122 123 124 125 126 127 128 129 130 131 135 // Tester 136 Methode m = (Methode)objet; return modifieurs == m.modifieurs && nom.equals(m.nom) && paramTypes.equals(m.paramTypes); 137 138 le cas où les modificateurs sont dans un ordre différent } 139 pour que ça marche avec HashSet ∗/ 141 /∗ Indispensable 142 public int hashCode() int result = 17; result = result * result = result * return result * 37 } 143 144 145 146 147 // // // // // 149 150 151 152 153 { 37 + modifieurs; 37 + nom.hashCode(); + paramTypes.hashCode(); Il reste à transformer les tableaux : [ Ljava . lang . Object ; en java . lang . Object [] par exemple , [ I pour int [], [ B pour boolean [], etc ... et aussi les tableaux à plusieurs dimensions : [[ I en int [][] public String toString() { return classeDefinition + ": " + Modifier.toString(modifieurs) + " " + transform(returnType) + " " + nom + "(" + paramTypes + ")"; } 154 155 156 157 158 159 } 161 private static String transform(String nomClasseCode) { if (!nomClasseCode.startsWith("[")) { return nomClasseCode; } 162 163 164 165 // C’est un tableau 166 int dimension = nomClasseCode.lastIndexOf("[") + 1; 168 String nomFinal; if (nomClasseCode.endsWith(";")) { 169 (??) Séance de TP n◦ 02– Réflexivité en Java 170 // C’est un tableau 171 nomFinal = nomClasseCode.substring(dimension + 1, nomClasseCode.length() 1); 172 11 de type non primitif } else { 173 174 175 // C’est un tableau 176 char typePrimitif = nomClasseCode.charAt(dimension); switch(typePrimitif) { case ’B’: nomFinal = "byte"; break; case ’C’: nomFinal = "char"; break; case ’D’: nomFinal = "double"; break; case ’F’: nomFinal = "float"; break; case ’I’: nomFinal = "int"; break; case ’J’: nomFinal = "long"; break; case ’S’: nomFinal = "short"; break; case ’Z’: nomFinal = "boolean"; break; case ’V’: nomFinal = "void"; break; default : nomFinal = "**type primitif inconnu**"; } 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 de type primitif } for (int i = 0; i < dimension; i++) { nomFinal += "[]"; } return nomFinal; 208 209 210 211 212 213 } 215 public static void main(String[] args) { String nomClasse = null; for (int i=0; i<args.length; i++) { try { nomClasse = args[i]; Class cl = Class.forName(nomClasse); System.out.println("Méthodes de la classe " + nomClasse); System.out.println("===================================================="); printMethods(cl, true); System.out.println(); } catch(ClassNotFoundException e) { System.out.println("Classe " + nomClasse + " pas trouvée."); } } } 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 } Séance de TP n◦ 02– Réflexivité en Java 12 Exercice 2 : une méthode toString générique pour les bébêtes Ecrivez, dans la classe BebeteAbstraite du précédent projet, une méthode : public String toString() {...} ...qui affiche le nom des attributs et leur valeur, mais sans en connaître le nombre ni le type à l’avance. N’essayez pas de voir les attributs hérités dans un premier temps. En effet, la méthode getDeclaredFields() de la classe Class ne retourne que les attributs locaux. Pour tester la méthode, faites par exemple afficher régulièrement les caractéristiques d’une bébête du simulateur sur la sortie standard (prenez par exemple la première bébête dans le moteur de simulation du ChampDeBebetes). Corrigé ⇒ On obtient les classes suivantes. Classe BebeteAbstraite 81 // 83 84 85 86 87 88 89 90 91 92 93 94 95 96 98 99 100 101 102 103 104 105 106 107 108 109 111 112 ajouts pour TD2 : réflexivité public String toString(){ Class cl = getClass(); String r = cl.getName() + FieldsFromClass(cl) +"\n"; Class[] allsc = allSuperClasses(cl); // cf plus loin for (int ci = 0; ci < allsc.length; ci++) { Class sc = allsc[ci]; r += allsc[ci].getName()+FieldsFromClass(allsc[ci])+"\n";; if (ci < allsc.length - 1) r += ","; else r += "]"; } return r; } // La reflexivité de Java ne donne pas la liste de toutes les superclasses : // Il faut parcours le chemin dhéritage entre la classe en remontant jusqu ’ à la // racine Object private static Class[] allSuperClasses(Class cl) { ArrayList rl = new ArrayList(); Class superC = cl.getSuperclass(); while (superC != null) { rl.add(superC); superC = superC.getSuperclass(); } return (Class [])(rl.toArray(new Class[0])); } private String FieldsFromClass(Class c) { String r = "[\n"; 113 // On ne prend que les champs locaux à la classe , quelque soit 114 Field[] fields = c.getDeclaredFields(); for (int i = 0; i < fields.length; i++){ Field f = fields[i]; r += "\t" + f.getName() + "="; try { r += f.get(this); } catch (IllegalAccessException e){ r += "???"; } 115 116 117 118 119 120 121 122 son modifieur Séance de TP n◦ 02– Réflexivité en Java if (i < fields.length - 1) r += "\n"; else r += "]"; 123 124 125 126 } System.out.println(r); return r; 127 128 129 } 130 132 } Classe ChampDeBebetes 1 /∗ ∗ 2 3 4 5 6 ∗ ChampDeBebtes : version pour des bebetes Emergentes avec toString Introspectif ∗ dans BebeteAbstraite : un click sur l ’ écran affiche la bebete à proximité , ∗ s ’ il y en a une. ∗ @author collet ( d’ après L. O’Brien , C. Reynolds & B. Eckel ) ∗/ 11 package tp1.bebetes; import java.awt.*; import java.util.*; import java.awt.event.MouseEvent; /∗ Nouveau TD2 ∗/ 13 public class ChampDeBebetes extends Panel implements Runnable { 8 9 10 15 16 17 18 20 21 22 24 25 26 27 28 private ArrayList lesBebetes; static int largeur = 0; static int hauteur = 0; static int nombreDeBebetes = 250; Thread leThread; Frame toStringFrame = null; /∗ Nouveau TD2 Afficheur ∗/ TextArea ta; /∗ Nouveau TD2 ∗/ public ChampDeBebetes(int largeur, int hauteur) { this .largeur = largeur; this .hauteur = hauteur; setSize(largeur, hauteur); lesBebetes = fabriqueBebetes(nombreDeBebetes); /∗ Ajout TD2 ∗/ 29 35 try { jbInit(); } catch(Exception e) { e.printStackTrace(); } 36 /∗ Fin Ajout TD2 ∗/ 37 leThread = new Thread(this); leThread.start(); 30 31 32 33 34 38 39 } 40 /∗ ... ∗/ 13 Séance de TP n◦ 02– Réflexivité en Java 131 /∗ ... 14 Ajout TD2 ∗/ private void jbInit() throws Exception { this .addMouseListener(new java.awt.event.MouseAdapter() { public void mousePressed(MouseEvent e) { this_mousePressed(e); } }); 133 134 135 136 137 138 139 } 141 void this_mousePressed(MouseEvent e) { if (toStringFrame == null) { 142 // création 143 de la petite fenêtre d’ affichage toStringFrame = new Frame("toString"); toStringFrame.setLocation(getX()+getWidth(),getY()); ta = new TextArea("...",20,60,TextArea.SCROLLBARS_NONE); ta.setEnabled(false); toStringFrame.add(ta,BorderLayout.CENTER); toStringFrame.pack(); toStringFrame.show(); } int mx = e.getX(); int my = e.getY(); 144 145 146 147 148 149 150 151 152 153 154 // Recherche de la bebete la plus proche de la position 155 ListIterator l = lesBebetes.listIterator(); if (lesBebetes.size() > 0) { BebeteAbstraite plusProche = (BebeteAbstraite)l.next(); float dmin = plusProche.distanceDepuisUnPoint(mx,my); while(l.hasNext()) { BebeteAbstraite b = (BebeteAbstraite)l.next(); float dminDeB = b.distanceDepuisUnPoint(mx,my); if (dminDeB < dmin) { dmin = dminDeB; plusProche = b; } } if (dmin > 30f) ta.setText("Pas de bébête à proximité"); else ta.setText(plusProche.toString()); } 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 } 172 /∗ Fin Ajout TD2 ∗/ 173 174 de la souris } Exercice 3 : un tableau grossissant Travail à effectuer Récupèrez le fichier “ArrayGrowTest.java”, tiré du livre Core Java ("au coeur de Java" dans la version française). 1 /∗ 2 3 4 ∗ Cay S. Horstmann & Gary Cornell , Core Java ∗ Published By Sun Microsystems Press / Prentice −Hall ∗ Copyright ( C) 1997 Sun Microsystems Inc . Séance de TP n◦ 02– Réflexivité en Java 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ∗ All Rights Reserved . ∗ ∗ Permission to use , copy , modify , and distribute this ∗ software and its documentation for NON−COMMERCIAL purposes ∗ and without fee is hereby granted provided that this ∗ copyright notice appears in all copies . ∗ ∗ THE AUTHORS AND PUBLISHER MAKE NO REPRESENTATIONS OR ∗ WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER ∗ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE ∗ IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ∗ PARTICULAR PURPOSE, OR NON−INFRINGEMENT. THE AUTHORS ∗ AND PUBLISHER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED ∗ BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING ∗ THIS SOFTWARE OR ITS DERIVATIVES. ∗/ 22 /∗ ∗ 23 24 25 26 ∗ @version 1.00 11 Mar 1997 ∗ @author Cay Horstmann ∗ petites modifs pour le TP... ∗/ 28 import java.lang.reflect.*; 30 public class ArrayGrowTest { public static void main(String[] args) { int [] a = { 1, 2, 3 }; Personne[] b = { new Personne("Maurice Chombier"), new Personne("François Pignon") }; 31 32 33 // a = ( int []) goodArrayGrow( a) ; // arrayPrint ( a) ; 34 35 b = (Personne[])goodArrayGrow(b); arrayPrint(b); 36 37 System.out.println ("The following call will generate an exception."); b = (Personne[])badArrayGrow(b); 39 40 41 42 } 44 static Object[] badArrayGrow(Object[] a) { int newLength = a.length * 11 / 10 + 10; Object[] newArray = new Object[newLength]; System.arraycopy(a, 0, newArray, 0, a.length); return newArray; } 45 46 47 48 49 static { 51 52 Object[] goodArrayGrow(Object []a) // CODE A ECRIRE ! 53 54 } 56 static void arrayPrint(Object a) { Class cl = a.getClass(); if (!cl.isArray()) return; Class componentType = a.getClass().getComponentType(); int length = Array.getLength(a); System.out.println(componentType.getName() + "[" + length + "]"); for (int i = 0; i < Array.getLength(a); i++) System.out.println(Array.get(a, i)); } 57 58 59 60 61 62 63 64 65 66 } 15 Séance de TP n◦ 02– Réflexivité en Java 68 69 class Personne { private String nom; public Personne(String nom) { this .nom = nom; } 71 72 73 public String toString() { return nom; } 75 76 77 78 16 } Complétez la méthode goodArrayGrow(...) pour qu’elle fonctionne. Dans un premier temps laissez les deux lignes : //a = (int[])goodArrayGrow(a); //arrayPrint(a); ...en commentaires. Ce que vous devez obtenir c’est : javaw ArrayGrowTest Personne[12] Maurice Chombier François Pignon null null ... The following call will generate an exception. java.lang.ClassCastException: [Ljava.lang.Object; at ArrayGrowTest.main(ArrayGrowTest.java:40) Exception in thread "main" Process ArrayGrowTest exited abnormally with code 1 Tous les "null" qui s’affichent sont normaux, ils prouvent que votre tableau a grossi. Décommentez maintenant les deux lignes correspondant au tableau de int. Ca devrait ne plus marcher... Essayez de faire quand même marcher le programme (aide: utilisez la classe Array) ! Corrigé ⇒ On obtient la classe suivante. Classe ArrayGrowTest 52 53 54 55 static Object goodArrayGrow(Object []a) // Attention ! Object [] n’ est pas du type Object // Pour faire le cast b = ( Personne []) badArrayGrow( b) // il vaut mieux que le type retourné soit de type Object 56 { Class cl = a.getClass(); 57 // On vérifie que l ’ objet a est bien de type Array pour lui appliquer // la méthode getComponentType () 58 59 if (!cl.isArray()) return null; 60 // Récupération 61 Class componentType = a.getClass().getComponentType(); du type des éléments et de la longueur Séance de TP n◦ 02– Réflexivité en Java 17 62 int length = Array.getLength(a); 63 // calcule 64 int newLength = length * 11 / 10 + 10; 66 // construction 67 Object newArray = Array.newInstance(componentType, newLength); de la nouvelle longueur du nouveau tableau 68 // recopie 69 System.arraycopy(a, 0, newArray, 0, length); return newArray; 70 71 des anciennes valeurs } 1. Pour ceux qui s’ennuient... • Terminez l’analyseur de classes pour qu’ils affichent correctement toutes les informations de généricité de la classe analysée. • Reprenez l’exercice 2, écrivez un écouteur du clic souris sur le champ de Bebetes, repérez la bébête la plus proche et affichez ses caractéristiques avec toString dans une fenêtre spécifique.