La généricité
(d’après le cours de Philippe GENOUD )
Cours de Programmation Orientée Objet Avancée
ISET Bizerte CHALOUAH Anissa
Anissa CHALOUAH
1
Généricité : motivation
Supposons que l'on développe du code pour gérer une file d'attente
(FIFO First In First Out) et que l'on veuille utiliser ce code pour
une file d'entiers une file de chaînes de caractères (String) une file d'objets Personne ,,,,,,,,,,,,
Anissa CHALOUAH
2
Généricité : motivation
1ère solution : écrire une classe pour chaque type de valeur que l'on peut mettre dans la file
class ElementInt { private final int value; private ElementInt next; ElementInt(int val) { this.value = val; next = null; } void inserer(ElementInt elt) { this.next = elt; } int getValue() { return value; } ElementInt getNext() { return next; } }
public class FileAttenteInt {
private ElementInt tête = null; private ElementInt queue = null; public void ajouter(int val) {
ElementInt elt = new ElementInt(val); if (estVide()) { tête = queue = elt; } else { queue.inserer(elt); queue = elt; } }
public boolean estVide() { return tête == null;} public int retirer() {
int val = -1; if (!estVide()) { val = tête.getValue(); tête = tête.getNext(); }
return val; }
}
Anissa CHALOUAH
3
Généricité : motivation
class ElementPersonne { private final Personnevalue; private ElementPersonne next; ElementPersonne(Personne val) { this.value = val; next = null; } void inserer(ElementPersonne elt) { this.next = elt; } int getValue() { return value; } ElementPersonne getNext() { return next; } ; }
public class FileAttentePersonne {
private ElementPersonne tête = null; private ElementPersonne queue = null; public void ajouter(Personne val) {
ElementPersonne elt = new ElementPersonne(val if (estVide()) { tête = queue = elt; } else { queue.inserer(elt); queue = elt; } }
public boolean estVide() { return tête == null public int retirer() {
int val = -1; if (!estVide()) { val = tête.getValue(); tête = tête.getNext(); }
return val; }
}
Anissa CHALOUAH
4
Généricité : motivation
1ère solution : écrire une classe pour chaque type de valeur que l'on peut mettre dans la
file
Duplication du code, source d'erreurs à l'écriture et lors de modifications du programme Nécessité de prévoir toutes les combinaisons possibles pour une application
Anissa CHALOUAH
5
Publicité
Généricité : motivation
2ème solution : utiliser un type "universel", Object en Java
class Element {
private final Object value; private Element next; Element(Object val) {
this.value = val; next = null;
} void inserer(Element elt) {
this.next = elt; }
public Object getValue() {
return value; }
public Element getNext() {
return next; }
}
public class FileAttente { private Element tête = null; private Element queue = null; public void ajouter(Object val) { Element elt = new Element(val); if (estVide()) { tête = queue = elt; }
else { queue.inserer(elt); queue = elt; } }
public boolean estVide() { return tête == null;} public Object retirer() {
Object val = null; if (!estVide()) { val = tête.getValue(); tête = tête.getNext(); }
return val; }
toute classe héritant de Object, il est possible d'utiliser FileAttente pour stocker n'importe quel type d'objet
}
Anissa CHALOUAH
6
Généricité : motivation
2ème solution : utiliser un type "universel", Object en Java
FileAttente f1 = new FileAttente(); f1.add(new Personne(...));
FileAttente f2 = new FileAttente(); f2.add(new Voiture(...));
Anissa CHALOUAH
7
Généricité : motivation
FileAttente f1 = new FileAttente(); f1.ajouter(new Personne(...)); ... // on veut récupérer le nom de la personne // en tête de file. String nom = (Personne)(f1.retirer()).getNom();
Transtypage
Object
f1.ajouter("Hello");
String nom = (Personne)(f1.retirer()).getNom();
ClassCastException
obligation pour le programmeur d'effectuer un transtypage lorsqu’il accède aux éléments de la file d'attente
pas de contrôle sur les valeurs rangées dans la file d'attente
code lourd, moins lisible, plus difficile à maintenir risques d’erreurs d’exécution.
Anissa CHALOUAH
8
Généricité : motivation
Mais ça, c'était avant…
Publicité
depuis la version 1.5 de java (Tiger), cela n’est qu’un mauvais souvenir grâce à
l’introduction (enfin !) de la généricité dans le langage Java.
Anissa CHALOUAH
9
Généricité : Principe
La généricité (ou polymorphisme paramétrique) permet de faire des abstractions sur
les types .
utiliser des types (Classes ou Interfaces) pour paramétrer une définition de classe ou d'interface
ou de méthode
réutiliser le même code avec des types de données différents.
Présente dans de nombreux langages de programmation avant introduction en Java :
Eiffel, Ada, C++, Haskell, ...
Présente dans le langage de modélisation UML
Anissa CHALOUAH
10
Les classes Element et FileAttente sont paramétrées en fonction d’un type formel T T est utilisé comme type d'une ou plusieurs caractéristiques. Les classes manipulent des
informations de type T. Elles ignorent tout de ces informations.
Anissa CHALOUAH
11
Utilisation d'une classe générique simple
Lors de l’instanciation de FileAttente<T> le type formel T est remplacé par un type
(Classe ou Interface) existant
Le type est passé en argument
FileAttente<Personne> f1 = new FileAttente<Personne> (); f1.add(new Personne(...));
FileAttente<Voiture> f2 = new FileAttente<> (); f2.add(new Voiture(...));
Depuis la version Diamond (java 7), on n'est pas obligé de mentionner les arguments de type dans le constructeur
Anissa CHALOUAH
12
Utilisation d'une classe générique simple
La généricité simplifie la programmation, évite de dupliquer du code et le rend plus robuste
Anissa CHALOUAH
13
Types Génériques Simples
Type générique : Classe ou interface paramétrée par un ou plusieurs types
classe générique à deux paramètres
public class Paire<T1, T2> {
private final T1 first; private final T2 second; public Paire(T1 first, T2 second)
{
this.first = first; this.second = second;
} public T1 getFirst() { return
first; }
Publicité
public T2 getSecond() { return
second; } }
Anissa CHALOUAH
Interface générique
public interface Comparable<T> {
int compareTo(T o);
}
14
Instanciation d'un type générique
Instanciation (invocation) d'un type générique consiste à valuer les paramètres de type Les arguments de type (paramètres effectifs) peuvent être :
des classes(concrètes ou abstraites) Paire<String, Forme> c1 = new Paire<>("Cercle 1",new Cercle(0,0,10));
des interfaces Paire<String, IDessinable> c2 = new Paire<>("Visage 1", new VisageRond());
des types paramétrés Paire<String, Paire<String,Forme>> = new Paire<>("Paire 3",c1);
des paramètres de type
public class FileAttente<E> { private Element<E> tête = null; ...
Anissa CHALOUAH
15
Compilation de code générique
compilation de code générique basée sur le mécanisme d'effacement (erasure)
Anissa CHALOUAH
16
Conséquences de l’effacement du type
à l'exécution, il n'existe qu'une classe (le type brut) partagée par toutes les instanciations du
type générique
mais cela induit un certain nombre de limitations
les membres statiques d'une classe paramétrée sont partagés par toutes les instanciations de celle-ci
Anissa CHALOUAH
17
Généricité : limitations
Les membres statiques d'une classe paramétrée ne peuvent pas utiliser ses paramètres de type au sein d'une classe paramétrée on ne peut pas utiliser les paramètre de type pour instancier un
objet (simple ou tableau)
Anissa CHALOUAH
18
Généricité : limitations
Seul le type brut est connu à l’exécution: au sein d'une classe paramétrée on ne peut pas utiliser les paramètre de type pour instancier un
objet (simple ou tableau)
Anissa CHALOUAH
19