document

publicité
634.1 / PROGRAMMATION Généricité – classes paramétrées Syntaxe Une classe peut être munie d'une liste de paramètres formels définissant les types dont elle dépend. Les identificateurs formels des types peuvent ensuite être employés dans la définition des composants de la classe, en lieu et place d'un nom de type constant. class MyClass0 <T0, T1> { T0 a; void m (T1 x) { /*...*/ } T0 f (int x) { /*...*/ } /*...*/ } // MyClass0 Une instance d'une telle classe est déclarée et créée en fournissant les paramètres effectifs correspondants aux types formels : ou encore : MyClass0<String, Integer> c0 = new MyClass0<String, Integer>(); MyClass0<Calendar, Object> c0 = new MyClass0<Calendar, Object>(); depuis Java 7 : MyClass0<String, Integer> c0 = new MyClass0<>(); MyClass0<Calendar, Object> c0 = new MyClass0<>(); ou encore : L'instance peut également être créée à l'ancienne : MyClass0 c0 = new MyClass0(); MyClass0 c1 = new MyClass0<String, Integer>(); MyClass0<String, Integer> c2 = new MyClass0(); Les trois instructions ci‐dessus provoquent la génération par le compilateur de Notes, soit à cause de l'instruction elle‐même, soit à cause de l'emploi d'une méthode de la classe. Les paramètres effectifs acceptés par une classe paramétrée peuvent également être limités à un type existant et à ses descendants (classe dérivée ou classe implantant une interface) : class MyClass1 <T extends ClasseMere> { /*...*/ } Une instance d'une telle classe doit être créée avec comme paramètre effectif ClasseMere ou une classe dérivée de celle‐ci (ou une classe implantant ClasseMere, si celle‐ci est une interface). Dans le cas où la restriction concerne plusieurs classes et/ou interfaces, la syntaxe est : class MyClass2 <T extends C0 & C1<T> & C2> { /*...*/ } Remarque sur l'instanciation Il n'est pas possible de créer des instances des types définis comme paramètres formels, pas plus qu'il n'est possible de créer des instances de tableaux ayant des composants de ces types. La compilation du code ci‐dessous : class Allocation <T> { void m () { T t0 = new T(); T[] t1 = new T[10]; } // m } // Allocation 634.1 – Programmation / P. Daehne produit les messages d'erreur : Allocation.java:3: unexpected type
found : type parameter T
required: class
T t0 = new T();
^
Allocation.java:4: generic array creation
T[] t1 = new T[10];
^
2 errors
1 / 2 Version 2.61 – 17.04.2015
Note lors de la compilation Avec les classes génériques, on obtient parfois un nouveau type de message d'avertissement lors de la compilation : une Note. Ce message nous signale qu'une opération de conversion de type unchecked ou unsafe est présente dans notre code ; le code est néanmoins généré. Note: OldColl.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
Cette situation survient lorsqu'on emploie un parameterized type à l'ancienne, c'est‐à‐dire qu'on en crée une instance sans préciser le ou les paramètres effectifs de type. La JVM considère alors ces composants comme étant un raw type, c'est‐à‐dire un type pour lequel aucune information n'est disponible à l'exécution et pour lequel les conversions automatiquement générées à la compilation pourraient échouer. En compilant avec l'option ‐Xlint:unchecked, le compilateur produit le message d'avertissement suivant : OldColl.java:27: warning: [unchecked] unchecked call to add(E) as a
member of the raw type java.util.ArrayList
if (!isIn(x)) {c.add(x);}
^
1 warning
Pour que le compilateur signale des erreurs (plutôt que des Notes) lors d'un mauvais usage des types paramétrés, il faut spécifier l'option de compilation: ‐Xlint:unchecked. Dès maintenant, toutes nos applications seront compilées avec cette option (dans NetBeans, il faut spécifier cette option dans les Properties du projet, compiling). Il est possible que, dans certaines circonstances, ces « erreurs » soient prévues :  Il y a des casts (type guards) nécessaires qui ne peuvent être vérifiés à l’exécution (parce que l’information n’existe pas dans le byte‐code) ; c’est le cas des type‐guards avec le parameterized type.  Dans ce cas, le compilateur produira un message d’avertissement (et le code ne sera pas généré).  L’annotation @SuppressWarnings("unchecked") permet de gérer cette situation. Lorsqu’elle préfixe une classe, une méthode ou une instruction, elle indique que le code de la classe, méthode ou instruction est type‐unsafe. Exemples : class Allocation <T> { @SuppressWarnings("unchecked") void m () { T[] t = (T[])new Object[10]; } // m } // Allocation class Allocation <T> { void m () { @SuppressWarnings("unchecked") T[] t = (T[])new Object[10]; } // m } // Allocation Exemples de mise en oeuvre Considérons le diagramme de classe suivant :  Implantation à l'ancienne: GestionClasseAncien.zip  Implantation en employant la version paramétrée des classes de bibliothèque ArrayList et Iterator: GestionClasseGen.zip  Implantation d'un groupe quelconque d'objets; mise en œuvre avec des Etudiants et des Voitures: GestionGroupes.zip 634.1 – Programmation / P. Daehne 2 / 2 Version 2.61 – 17.04.2015
Téléchargement