@Judith
Benzakki
La généricité
Nouveauté la plus significative du langage Java depuis la version 1.0.
Permet d'écrire du code plus sûr et plus facile à lire qu'un code parsemé de variables Object et de
cast
Particulièrement utile pour les classes de collection, comme ArrayList<E>
La programmation générique implique d'écrire du code qui puisse être réutilisé pour des objets
de types différents
Inutile, par exemple, de programmer des classes différentes pour collecter les objets String et File,
puisque dorénavant, la classe ArrayList<E> collecte les objets de n'importe quelle classe
Avant le JDK 5.0
La programmation équivalente à la programmation générique s'obtenait à chaque fois par le
mécanisme d'héritage
Ainsi, la classe ArrayList conservait simplement un tableau de références Object
1 public class ArrayList { // Avant le JDK 5.0
2 public Object get(int indice) { ... }
3 public void add(Object élément) { ... }
4 }
Cette approche présente deux problèmes :
D'une part, il faut avoir recours au transtypage (cast) pour récupérer un objet :
ArrayList fichier = new ArrayList() ;
...
String nomFichier = (String) fichier.get(0) ;
D'autre part, il n'existe aucune procédure de vérification des erreurs
On peut ajouter des valeurs de n'importe quelle classe :
fichier.add(new File("...")) ;
Cet appel compile et s'exécute sans erreur
Exemple avant la généricité
1 public class ExempleGenericite {
2 private String Attribut;
3 public ExempleGenericite(){
4 this.Attribut = "";
5 }
6 public ExempleGenericite(String Attribut){
7 this.Attribut = Attribut;
8 }
9 public String getAttribut {
10 return Attribut;
11 }
12 public void setAttribut(String Attribut) {
13 this.Attribut = Attribut;
14 }
15 }
1 // À l'utilisation
2 // si je veux créer un objet de cette classe et l'afficher
3 public static void main () {
4 ExempleGenericite exemple = new ExempleGenericite("toto");
5 System.out.println (exemple.getAttribut());
6 ExempleGenericite exemple2 = new ExempleGenericite();
7 exemple2.seAttribut("tata")
8 System.out.println (exemple2.getAttribut());
9 }
10
Remarque
Ce code fonctionne uniquement avec des String !
Comment faut-il faire si je veux créer des objets de n'importe quel type ?
Solution avant la généricité
En utilisant des Object :
1 public class ExempleGenericite {
2 private Object Attribut;
3 public ExempleGenericite(){
4 this.Attribut = null;
5 }
6 public ExempleGenericite(Object Attribut){
7 this.Attribut = Attribut;
8 }
9 public Object getAttribut {
10 return Attribut;
11 }
12 public void setAttribut(Object Attribut) {
13 this.Attribut = Attribut;
14 }
15 }
1 // À l'utilisation
2 // si je veux créer un objet de cette classe et l'afficher
3 public static void main () {
4 ExempleGenericite exemple = new ExempleGenericite("toto");
5 String test = exemple.getAttribut()); // ERREUR car Attribut est de type
Object donc
6 String test = (String) exemple.getAttribut()); // CAST obligatoire
7 ExempleGenericite exemple2 = new ExempleGenericite();
8 exemple2.seAttribut(15.2);
9 Double value = (Double) exemple2.getAttribut();
10
11 }
Avec la généricité
plus besoin de castdes objets
vérification à la compilation
1 public class ExempleGenericite<T> { // pour l'instant on ne connait pas le type
<T>
2 private T Attribut;
3 public ExempleGenericite(){
4 this.Attribut = null;
5 }
6 public ExempleGenericite(T Attribut){
7 this.Attribut = Attribut;
8 }
9 public T getAttribut {
10 return Attribut;
11 }
12 public void setAttribut(T Attribut) {
13 this.Attribut = Attribut;
14 }
15 }
1 // À l'utilisation
2 // si je veux créer un objet de cette classe et l'afficher
3 public static void main () {
4 ExempleGenericite <String> exemple = new ExempleGenericite("toto");
5 String test = exemple.getAttribut()); // Plus de CAST
6 ExempleGenericite <Double> exemple2 = new ExempleGenericite();
7 exemple2.seAttribut(15.2);
8 Double value = exemple2.getAttribut();
9
10 }
Remarque
On peut avoir plusieurs types <T,E> :
Exemple avec les HashMap<K,V> ; Kest la clé, Vla valeur (Objet)
sur notre exemple :
1 public class ExempleGenericite<T,E>
2 private T Attribut;
3 private E Attribut2;
1 ExempleGenericite<String,Double> exemple = new ExempleGenericite("toto", 2.34)
Méthodes génériques
On peut définir des méthodes avec des paramètres de type :
1 public static <T> T getMilieu(T[] tableau) {
2 return tableau[tableau.length / 2];
3 }
Cette méthode est définie dans une classe ordinaire
C'est une méthode générique
Les paramètres de type sont insérés après les modificateurs et avant le type de retour
Appel d'une méthode générique
1 String[] noms= {"Marie", "possède", "une", "petite", "lampe"};
2 String milieu = TableauAlg.<String>getMilieu(noms) ;
Dans ce cas, on peut omettre le paramètre type <String> de l'appel de méthode
Le compilateur dispose de suffisamment d'informations pour en déduire la méthode que l’on souhaite
On peut donc simplement écrire :
String milieu = TableauAlg.getMilieu(noms)
Programmation générique
Limites pour les variables de type
On a besoin de placer des restrictions sur des variables de type :
1 public static <T> T min (T[] tab) {
2 If (tab ==null || tab.length==0) return null;
3 T pluspetit = tab[0];
4 for (T val : tab)
5 if (pluspetit.compareTo(val)>0) pluspetit = val;
6 return pluspetit;
7 }
Remarque
Que se passe-t-il avec cette méthode min()?
la variable pluspetitpossède un type T, ce qui signifie qu’il pourrait s’agit d’un type ordinaire
Comment savoir que Tpossède une méthode compareTo()?
Essayez ce code et commentez
Solution
Il faut restreindre Tà une classe qui implémente l’interface Comparable
1 public static <T entends Comparable> T min (T[] tab)
La notation
<T entends typeLimitant>
indique que Tdoit être un sous-type du typeLimitant
Tet le typeLimitant peuvent être une classe ou une interface
le mot clé extendsa été choisi car il constitue une approximation raisonnable du concept de sous
type.
Une variable peut avoir plusieurs limites : <T entends Comparable & Serializable>
Exercice
Écrire une méthode minmax()
Compléments