Les "Generics" depuis le JDK 5
But: écrire du code utilisable avec n'importe quel type de données :
- classe générique
- méthode générique
Rappel:
- le modèle n'est pas compilé mais inclus
- l'expansion du code est faite à la compilation à partir du type effectif sur lequel il porte et autant de fois qu'il y a de types différents utilisés avec le modèle.
En Java:
- notion d'effacement: tout type générique devient le type Object donc le modèle peut être compilé
- un seul "bytecode" fourni
- le transtypage est assuré à la compilation du code.
Ceci impose quelques limites:
- le type effectif utilisé doit être une classe
- on ne peut pas instancier un objet générique à l'intérieur d'une classe générique
- un type générique ne peut pas être static
Les conteneurs avec le JDK 5
Problème des conteneurs avant le JDK 5 :
- les éléments sont de type Object
- pas moyen de déclarer une collection d'un type donné
- on peut stocker n'importe quelle instance de classe
- il faut transtyper en permanence entre le type
- Object et le type utilisé
- les erreurs de type ClassCastException ne sont pas repérées qu'à l'exécution
Depuis le JDK 5 :
- les collections sont paramétrées
- vérification du typage à la compilation : collection homogène
- on évite les transtypages qui alourdissent le code
- MAIS pour des raisons de compatibilité les collections non génériques sont supportées
Principales nouveautés:
- conteneurs génériques
- nouvelle boucle for mais uniquement pour les classes qui implémentent l'interface Iterable<T>
- nouvelle interface Queue
[...] Les nouveautés JAVA 5 Les "Generics" depuis le JDK 5 Présentation But: écrire du code utilisable avec n'importe quel type de données classe générique méthode générique Rappel: avec les templates du le modèle n'est pas compilé mais inclus l'expansion du code est faite à la compilation à partir du type effectif sur lequel il porte et autant de fois qu'il y a de types différents utilisés avec le modèle Présentation En Java: approche différente notion d'effacement: tout type générique devient le type Object donc le modèle peut être compilé un seul "bytecode" fourni le transtypage est assuré à la compilation du code Ceci impose quelques limites le type effectif utilisé doit être une classe on ne peut pas instancier un objet générique à l'intérieur d'une classe générique un type générique ne peut pas être static Classe générique Définition: exemple avec un type paramétré class MaClasseGenerique . [...]
[...] tableau qui implémente la pile Individu tIndividu=new Individu[5]; Joker simple Pile unePile = new Pile (tIndividu); appel à la méthode empiler refusé à la compilation unePile.empiler(new Individu("dugommier","robert")); unePile.empiler(new Individu("tartempion","albert")); System.out.println("\n On depile les individus"); while unePile.estVide()) erreur: dépiler rend un Object cast obligatoire unePile.depiler().affiche(); Les conteneurs avec le JDK 5 Présentation Problème des conteneurs avant le JDK 5 les éléments sont de type Object pas moyen de déclarer une collection d'un type donné on peut stocker n'importe quelle instance de classe il faut transtyper en permanence entre le type Object et le type utilisé les erreurs de type ClassCastException ne sont pas repérées qu'à l'exécution Présentation Depuis le JDK 5 les collections sont paramétrées vérification du typage à la compilation collection homogène on évite les transtypages qui alourdissent le code MAIS pour des raisons de compatibilité les collections non génériques sont supportées Principales nouveautés conteneurs génériques nouvelle boucle for mais uniquement pour les classes qui implémentent l'interface Iterable nouvelle interface Queue Classe Vector Collection d'objets de type E gérée par un tableau de taille variable la classe Vector implémente en particulier les interfaces List Collection Iterable principales méthodes supportées: insertion, suppression, recherche, extraction d'un élément voir la documentation Classe Vector Classe Vector Classe Vector Classe ArrayList Classe plus simple que Vector implémente les mêmes interfaces que Vector principales méthodes supportées: insertion, suppression, recherche, extraction d'un élément voir la documentation Différence importante cependant comme les autres collections, ArrayList n'est pas synchronized alors que Vector l'est ce qui peut entrainer des incohérences avec un programme multi-threads (voir chapitre sur les threads) Classe ArrayList Classe ArrayList Classe HashMap Classe HashMap Classe HashMap Classe HashMap Classe HashMap Classe HashMap Classe TreeMap Classe TreeMap Classe TreeMap Modèle par défaut Les nouveautés JAVA 5 Les "Generics" depuis le JDK 5 Présentation But: écrire du code utilisable avec n'importe quel type de données classe générique méthode générique Rappel: avec les templates du le modèle n'est pas compilé mais inclus l'expansion du code est faite à la compilation à partir du type effectif sur lequel il porte et autant de fois qu'il y a de types différents utilisés avec le modèle Présentation En Java: approche différente notion d'effacement: tout type générique devient le type Object donc le modèle peut être compilé un seul "bytecode" fourni le transtypage est assuré à la compilation du code Ceci impose quelques limites le type effectif utilisé doit être une classe on ne peut pas instancier un objet générique à l'intérieur d'une classe générique un type générique ne peut pas être static Classe générique Définition: exemple avec un type paramétré class MaClasseGenerique . [...]
[...] true : false; } } fin classe Pile Exemple d'une classe générique Exemple d'utilisation try { System.out.println("\n\n On crée une pile d'individus Individu tIndividu=new Individu[3]; Pile pileIndividus; pile d'Invidus pileIndividus = new Pile(tIndividu); pileIndividus.empiler(new Individu("dupont","jean")); pileIndividus.empiler(new Individu("durand","pierre")); System.out.println("\n On depile while pileIndividus.estVide()) pileIndividus.depiler().affiche(); } catch (PileException { System.out.println("\n "+e.getMessage()+"\n\n"); } Exemple d'une classe générique Quelques remarques sur la classe Pile (ici : simple illustration car le JDK dispose déjà d'une classe générique Stack) le type paramétré E aurait pu être contraint (par exemple pour imposer que les types effectifs dérivent de Number) l'allocation du tableau qui représente le contenu de la pile par : new E[taille] est interdite dans l'exemple c'est l'appelant qui s'en charge il serait possible de faire un tableau d'objets grâce à laPile=(E new Object[taille] dans le constructeur mais cela génèrerait un warning Exemple d'une classe générique Exemple de méthode générique Exemple de méthode générique Dérivation de classe générique Règles de dérivation correctes Class B extends A Class B extends A Class B extends A Class B extends A Class B extends A Règles de dérivation incorrectes Class B extends A Class B extends A Class B extends A Dérivation de classe générique ATTENTION: si T2 dérive de T1 alors G ne dérive pas nécessairement de G si G dérivait de G on pourrait affecter une instance de G à une référence de G supposons que la classe générique G dispose d'une méthode modifiant la valeur du type paramétré un type T2 pourrait alors être transformé en type T1 via la référence de G et donc l'instance de G disposerait d'un type T1 ce qui serait incorrect Joker Pour contourner ce problème Java propose le mécanisme d'instanciation avec joker (wildcard) un joker est représenté par il désigne un type paramétré inconnu quelconque Il sert UNIQUEMENT à instancier un type générique: variable, paramètre, retour de méthode, tableau (sous certaine condition) Le compilateur impose des règles précises sur les types lors d'une instanciation avec joker Joker Joker contraint par les deux contraintes d'instanciation sont réunies supposons que l'on veuille instancier un générique G avec le type comme type E l'appel à toute méthode recevant un paramètre de type E est interdite (sauf valeur null) toute méthode qui retourne un type E ne peut être affectée qu'à un type Object Joker Instanciation de Pile avec ? [...]
[...] } Utilisation d'une classe générique déclaration d'une référenceMaClasseGenerique maRef; instanciation de la classe génériquemaRef = new MaClasseGenerique (unObjet); remarque: dans cet exemple le constructeur de la classe générique n'a besoin que d'un seul paramètre unObjet instance de UneClasse Méthode générique Il est également possible de définir des méthodes génériques static type_retour méthode(T arg ) . [...]
[...] true : false; } } fin classe Pile Exemple d'une classe générique Exemple d'utilisation try { System.out.println("\n\n On crée une pile d'individus Individu tIndividu=new Individu[3]; Pile pileIndividus; pile d'Invidus pileIndividus = new Pile(tIndividu); pileIndividus.empiler(new Individu("dupont","jean")); pileIndividus.empiler(new Individu("durand","pierre")); System.out.println("\n On depile while pileIndividus.estVide()) pileIndividus.depiler().affiche(); } catch (PileException { System.out.println("\n "+e.getMessage()+"\n\n"); } Exemple d'une classe générique Quelques remarques sur la classe Pile (ici : simple illustration car le JDK dispose déjà d'une classe générique Stack) le type paramétré E aurait pu être contraint (par exemple pour imposer que les types effectifs dérivent de Number) l'allocation du tableau qui représente le contenu de la pile par : new E[taille] est interdite dans l'exemple c'est l'appelant qui s'en charge il serait possible de faire un tableau d'objets grâce à laPile=(E new Object[taille] dans le constructeur mais cela génèrerait un warning Exemple d'une classe générique Exemple de méthode générique Exemple de méthode générique Dérivation de classe générique Règles de dérivation correctes Class B extends A Class B extends A Class B extends A Class B extends A Class B extends A Règles de dérivation incorrectes Class B extends A Class B extends A Class B extends A Dérivation de classe générique ATTENTION: si T2 dérive de T1 alors G ne dérive pas nécessairement de G si G dérivait de G on pourrait affecter une instance de G à une référence de G supposons que la classe générique G dispose d'une méthode modifiant la valeur du type paramétré un type T2 pourrait alors être transformé en type T1 via la référence de G et donc l'instance de G disposerait d'un type T1 ce qui serait incorrect Joker Pour contourner ce problème Java propose le mécanisme d'instanciation avec joker (wildcard) un joker est représenté par il désigne un type paramétré inconnu quelconque Il sert UNIQUEMENT à instancier un type générique: variable, paramètre, retour de méthode, tableau (sous certaine condition) Le compilateur impose des règles précises sur les types lors d'une instanciation avec joker Joker Joker contraint par les deux contraintes d'instanciation sont réunies supposons que l'on veuille instancier un générique G avec le type comme type E l'appel à toute méthode recevant un paramètre de type E est interdite (sauf valeur null) toute méthode qui retourne un type E ne peut être affectée qu'à un type Object Joker Instanciation de Pile avec ? [...]
Source aux normes APA
Pour votre bibliographieLecture en ligne
avec notre liseuse dédiée !Contenu vérifié
par notre comité de lecture