Généricité et Collections en Java
Généricité et Collections en Java
– Cours –
Chapitre 4 : Généricité et collections
ZERARI Mounira
NTIC/Département MI
[Link]@[Link]
– Cours 4 –
Chapitre 4 : Généricité et Collection.
ZERARI Mounira
NTIC/Département MI
[Link]@[Link]
Etudiants
concernés
Faculté/Institut Département Niveau Spécialité
Université Constantine 2 5
Généricité: Principe de base
Cas de classe: permettant d'illustrer les bases de
la généricité.
Affecter une valeur, la mettre à jour et la
récupérer.
Question: Faire une classe qui permet de
travailler avec n'importe quel type de données
Université Constantine 2 6
Généricité: Principe de base
Down cast implicite: Erreur à la compilation.
Université Constantine 2 7
Généricité: Principe de base
Université Constantine 2 8
Généricité: Principe de base
T n'est pas encore défini.
une fois instancié avec un type, l'objet ne pourra
travailler qu'avec le type de données que vous
lui avez spécifié !
Université Constantine 2 9
Généricité: Effacement
Université Constantine 2 10
Généricité: Effacement
Couple<String> cs = new Couple<String> (.....) ;
Couple<Double> cd = new Couple<Double> (.....) ;
//true
cs instanceOf Couple
//true
cd instanceOf Couple
La valeur de compte va s’accroître à
chaque instanciation d’un objet de type
Couple: Couple<Point>,
Couple<Double>...
Université Constantine 2 11
Généricité: Méthode générique
Effacement du type T,
Université Constantine 2 12
Généricité: Limitation des paramètres Type
Université Constantine 2 13
Généricité: Limitation des paramètres Type
Université Constantine 2 14
Généricité: Limitation des paramètres Type
• Classe générique méthode générique, peut
imposer à une classe correspondant à un paramètre
de type, non seulement de dériver d’une classe
donnée, mais aussi d’implémenter une interface:
class Couple <T extends Comparable> // T doit implémenter l’interface Comparable { ..... }
Université Constantine 2 15
Généricité et héritage: Réflexion
Nous avons :
Object o = …; Integer i = …; o = i ; // correct !
Université Constantine 2 16
Généricité et héritage: Réflexion
Université Constantine 2 17
Généricité et héritage: Polymorphisme
Université Constantine 2 18
Généricité et héritage: Les Jokers
Université Constantine 2 19
Généricité et héritage: Joker simple
classe Couple1<T>:
Mais, on peut également définir :
Université Constantine 2 22
Section 2 :
Les collections
Université Constantine 2 24
Généricité
• Avant le JDK 5.0, il n’était pas possible d’indiquer
qu’une collection du JDK ne contenait que des objets
d’un certain type ; les objets contenus étaient
déclarés de type Object
• A partir du JDK 5.0, on peut indiquer le type des
objets contenus dans une collection grâce à la
généricité : List<Employe>
• Il est préférable d’utiliser les collections génériques
Université Constantine 2 25
Cadre de Collections Java
• Un framework qui définit:
• Des interfaces: qui représentent les collections
• Des classes abstraites: qui implantent les méthodes de
base communes aux interfaces.
• Des réalisations (implémentations) : réalisations concrètes
des interfaces en s’appuyant sur différentes solutions pour
stocker les éléments (tableau, structures chaînées, table de
hachage, arbre, etc.).
• Des algorithmes : algorithmes classiques (chercher, trier, etc.)
polymorphes (fonctionnent avec plusieurs collections)
• Un protocole d’itération : pour parcourir une collection du
début à la fin.
Université Constantine 2 26
Hiérarchie des Collections en Java
Université Constantine 2 27
Les interfaces
• Des interfaces dans 2 hiérarchies d’héritage principales:
• Collection<E>
• Map<K,V>
• Collection correspond aux interfaces des collections
proprement dites
• Map correspond aux collections indexées par des clés ;
un élément de type V d’une map est retrouvé
rapidement si on connaît sa clé de type K (comme les
entrées de l’index d’un livre)
Université Constantine 2 28
Les interfaces
Université Constantine 2 29
Les classes abstraites
• AbstractCollection<E>, AbstractList<E>,
AbstractMap<K,V>,… implantent les méthodes de
base communes aux interfaces Collection ou Map
Université Constantine 2 30
Les réalisations (classes concrètes)
Université Constantine 2 31
Les réalisations (classes concrètes)
• Le framework fournit les implémentations suivantes
des différentes interfaces:
Université Constantine 2 32
Classes utilitaires
• La classe Collections (avec un s à la fin) fournit des
méthodes statiques pour, en particulier
• trier une collection
• faire des recherches rapides dans une collection triée
Université Constantine 2 33
Classes utilitaires: Classe Collections
Université Constantine 2 34
Exemple détaillé
Université Constantine 2 35
Généricité et héritage
public static void main(String[] args) {
List<Voiture> listVoiture = new ArrayList<Voiture>();
List<VoitureSansPermis> listVoitureSP = new
ArrayList<VoitureSansPermis>();
listVoiture = listVoitureSP;
//Interdit !
}
Université Constantine 2 36
Généricité et héritage
• Une des solutions consiste à utiliser le wildcard : ?.
• Le fait de déclarer une collection avec le wildcard,
comme ceci : ArrayList<?> list; revient à indiquer que
notre collection accepte n'importe quel type d'objet.
Lecture seule.
Université Constantine 2 37
Généricité et héritage
static void affiche(List<? super Voiture>list){
for(Object v : list)
[Link]([Link]());
}
Université Constantine 2 38
Sous-typage et généricité:
• Puisque ArrayList<E> implémente List<E>, ArrayList<E> est
un sous-type de List<E>
• Ceci est vrai pour tous les types paramétrés construits à
partir de ces 2 types
• Par exemple, ArrayList<Personne> est un sous-type de
List<Personne> ou ArrayList<Integer> est un sous-type de
List<Integer>
• Mais attention, si B hérite de A, les classes ArrayList<B> et
ArrayList<A> n’ont aucun lien de sous-typage entre elles.
• Exemple : ArrayList<Integer> n’est pas un sous-type de
ArrayList<Number> !! (Number est la classe mère de
Integer)
Université Constantine 2 39
Généricité et héritage
import [Link];
import [Link];
public class Garage {
List<Voiture> list = new ArrayList<Voiture>();
public void add(List<? extends Voiture> listVoiture){
for(Voiture v : listVoiture) [Link](v);
[Link]("Contenu de notre garage :");
for(Voiture v : list)
[Link]([Link]());
}
}
public static void main(String[] args){
List<Voiture> listVoiture = new ArrayList<Voiture>();
[Link](new Voiture());
List<VoitureSansPermis> listVoitureSP = new
ArrayList<VoitureSansPermis>();
[Link](new VoitureSansPermis());
Garage garage = new Garage();
[Link](listVoiture);
[Link]("--------------------------");
[Link](listVoitureSP);
}
Université Constantine 2 40
Collection polymorphe
• Une collection polymorphe est une collection qui contient
des objets de classes d'appartenances différentes.
• Il existe deux façons de créer une classe polymorphe :
• toutes les classes d'appartenance des objets de la liste
polymorphe héritent d'une même classe abstraite, et le type de la
collection est cette classe abstraite
• toutes les classes d'appartenance des objets de la liste
polymorphe implémentent une même interface, et le type de la
collection est cette interface.
• Soit les classes A et B qui héritent de
C. Les classes A et B ne sont pas
abstraites. La classe C est abstraite:
ArrayList<C> elements; [Link](new A() );
[Link]( new B() )
Université Constantine 2 41
Ordre des éléments d’une collection
• Besoin de classer les éléments à partir de leur valeur.
• Recherche de maximum ou de minimum.
• Tri.
• Les méthodes concernées considèrent par défaut que
ses éléments implémentent l’interface Comparable
(Comparable<E> depuis le JDK 5.0) et recourent à sa
méthode compareTo.
• Une méthode de comparaison appropriée par le biais
de ce qu’on nomme un objet comparateur.
Université Constantine 2 42
Utilisation de la méthode compareTo
• Certaines classes comme String, File ou les classes
enveloppes (Integer, Float...) implémentent l’interface
Comparable et disposent donc d’une méthode
compareTo.
• Dans ce cas, cette dernière fournit un résultat qui
conduit à un ordre qu’on peut qualifier de naturel :
• ordre lexicographique pour les chaînes, les noms de fichier
ou la classe Character,
• ordre numérique pour les classes enveloppes numériques.
Université Constantine 2 43
Exemple: Tri
ArrayList<Livre> liste2 = new ArrayList<Livre>();
[Link](new Livre("SF","DUNE"));
[Link](new Livre("ROMAN","KGB"));
[Link](new Livre("ROMAN","A MORT"));
[Link](new Livre("SF","ALARME"));
[Link](liste2);
class Livre implements Comparable<Livre>
{
String titre;
String genre;
public Livre(String genre, String titre)
{
[Link]=titre;
[Link]=genre;
}
public int compareTo(Livre l)
{
if ([Link]([Link])>0)
return(1);
else if ([Link]([Link])<0)
return(-1);
else if ([Link]([Link])>0)
return(1);
else if ([Link]([Link])<0)
return(-1);
else
return(0);
}
public String toString()
{
return genre+" / "+titre;}}
Université Constantine 2 44
Utilisation d’un objet comparateur
• Les éléments sont des objets d’une classe existante qui
n’implémente pas l’interface Comparable,
• On a besoin de définir plusieurs ordres différents sur une
même collection.
• Il est alors possible de définir l’ordre souhaité, non plus
dans la classe des éléments mais :
• soit lors de la construction de la collection,
• soit lors de l’appel d’un algorithme.
• public int compare (E o1, E o2)
Université Constantine 2 45
Exemple: Max selon deux critères
[Link] [Link].* ;
[Link] class MaxMin
3.{ public static void main (String args[])
4.{ Point p1 = new Point (1, 3) ; Point p2 = new Point (2, 1) ;
[Link] p3 = new Point (5, 2) ; Point p4 = new Point (3, 2) ;
[Link] <Point> l = new LinkedList <Point> () ;
[Link] (p1) ; [Link] (p2) ; [Link] (p3) ; [Link] (p4) ;
/* max de l, suivant l’ordre défini par compareTo de Point */
[Link] pMax1 = [Link](l) ;
[Link] ("Max suivant compareTo = ") ; [Link]() ;
[Link] () ;
/* max de l, suivant l’ordre defini par un comparateur anonyme */
[Link] pMax2 = (Point)[Link] (l, new Comparator()
12.{ public int compare (Object o1, Object o2)
13.{ Point p1 = (Point) o1 ; Point p2 = (Point) o2 ;
[Link] (p1.y < p2.y) return -1 ;
[Link] if (p1.y == p2.y) return 0 ;
[Link] return 1 ;}}) ;
[Link] ("Max suivant comparator = " ) ; [Link]() ;}}
Université Constantine 2 46
Exemple: Max selon deux critères
class Point implements Comparable
{ Point (int x, int y) { this.x = x ; this.y = y ; }
public void affiche ()
{ [Link] ("[" + x + " " + y + "] ") ;
}
public int compareTo (Object pp)
{ Point p = (Point) pp ;
if (this.x < p.x) return -1 ;
else if (this.x == p.x) return 0 ;
else return 1 ;
}
public int x, y ; // public ici, pour simplifier les choses
}
Université Constantine 2 47
Opérations communes à toutes les collections
Université Constantine 2 48
Opérations communes à toutes les collections
Université Constantine 2 49
Opérations communes à toutes les collections
Université Constantine 2 50
Qu’est ce qu’un « Itérateur »?
• Un itérateur (instance d’une classe qui implante
l’interface Iterator<E>) permet d’énumérer les
éléments contenus dans une collection
• Il encapsule la structure de la collection
• Permet de parcourir tous les éléments d’une collection (en
analogie avec le parcours d’un tableau).
Université Constantine 2 51
Qu’est ce qu’un « Itérateur »?
• objets qui permettent de "parcourir" un par un les
différents éléments d’une collection.
• Ils ressemblent à des pointeurs.
• Il existe deux sortes d’itérateurs :
• monodirectionnels : le parcours de la collection se fait d’un
début vers une fin ; on ne passe qu’une seule fois sur
chacun des éléments ;
• bidirectionnels : le parcours peut se faire dans les deux
sens ; on peut avancer et reculer à sa guise dans la
collection.
Université Constantine 2 52
Qu’est ce qu’un « Itérateur »?
• Pour pouvoir itérer sur une collection, il faut qu'elle soit
itérable, c'est à dire qu'elle hérite de Iterable.
public interface Iterable<E> {
Iterator<E> iterator();}
Université Constantine 2 53
L’interface [Link]<E>
• Cette interface définit des méthodes pour des objets
capables de parcourir les données d'une collection:
• boolean hasNext(): retourne true s'il reste au moins un
élément à parcourir dans la collection
• E next(): renvoie l'élément courant dans le parcours et passe
l'itérateur à l'élément suivant (lance NoSuchElementException
lorsqu’il n'y a plus rien à renvoyer)
• void remove(): supprime le dernier élément parcouru (next
doit être appelé avant).
Iterator<E> iter = [Link]() ;
Iterator<E> iter = [Link] () ; while ([Link]())
while ( [Link]() ) { E = [Link]() ;
{ E o = [Link] () ; if (condition) [Link]() ;
// utilisation de o }
}
Université Constantine 2 54
L’interface [Link]<E>
Université Constantine 2 55
L’interface [Link]<E>
Université Constantine 2 56
Structure Générale
Université Constantine 2 57
L’interface Set<E>
• Correspond à une collection qui ne contient pas 2 objets
égaux au sens de equals (comme les ensembles des
mathématiques).
• Exemple, elle n'accepte qu'une seule fois null, car deux
valeurs null sont considérées comme un doublon.
• On fera attention si on ajoute des objets modifiables : la
non duplication d’objets n’est pas assurée dans le cas où
on modifie les objets déjà ajoutés.
Université Constantine 2 58
L’interface Set<E>
• Classes qui implémentent cette interface :
• Les Set sont particulièrement adaptés pour manipuler une grande quantité
de données. Cependant, les performances de ceux-ci peuvent être
amoindries en insertion. Généralement, on opte pour un HashSet, car il est
plus performant en temps d'accès, mais si vous avez besoin que votre
collection soit constamment triée, optez pour un TreeSet.
Université Constantine 2 59
Méthode de Set<E>
• Mêmes méthodes que l’interface Collection.
• Mais les « contrats » des méthodes sont adaptés aux
ensembles.
• Par exemple,
– la méthode add n’ajoute pas un élément si un
élément égal est déjà dans l’ensemble (la méthode
renvoie alors false).
– quand on enlève un objet, tout objet égal (au
sens de equals) à l’objet passé en paramètre sera
enlevé.
• Le comportement du Set peut être altéré si un objet
placé dans un Set est modifié d’une manière qui
affecte la valeur renvoyée par equals
Université Constantine 2 60
La classe HashSet<E>
• La plus utilisée des implémentations de l'interface
Set.
• HashSet hérite de la classe abstraite AbstractSet et
implémente l'interface [Link].
• La classe HashSet crée une collection d'objets qui
utilise une table de hachage pour le stockage.
• Une table de hachage stocke les valeurs en leurs
donnant une clé unique pour les identifier.
• Une clé ne peut pas être associée à deux valeurs
contrairement à HashMap.
Université Constantine 2 61
HashSet<E>: Construction et parcours
• Constructeurs
// ensemble vide
HashSet<E> e1 = new HashSet<E> ()
// ensemble contenant tous les elements de la collection c
HashSet<E> e2 = new HashSet<E>(c) ;
// ensemble vide
TreeSet<E> e3 = new TreeSet<E>() ;
// ensemble contenant tous les elements de la collection c
TreeSet<E> e4 = new TreeSet<E>(c) ; //
• Les deux classes HashSet et TreeSet disposent de la méthode
iterator prévue dans l’interface Collection.
•Elle fournit un itérateur monodirectionnel (Iterator) permettant de
parcourir les différents éléments de la collection :
HashSet<E> e ; // ou TreeSet<E> e
.....
Iterator<E> it = [Link]() ;
while ([Link]())
{ E o = [Link]() ;
// utilisation de o}
Université Constantine 2 62
HashSet<E>:
import [Link].* ;
Construction et parcours
public class Ens1
{ public static void main (String args[])
{ int t[] = {2, 5, -6, 2, -8, 9, 5} ;
HashSet<Integer>ens = new HashSet<Integer>() ;
/* on ajoute des objets de type Integer */
for (int v : t)
{ boolean ajoute = [Link](v) ;
if (ajoute) [Link] (" On ajoute " + v) ;
else [Link] (" " + v + " est deja present") ;}
[Link] ("Ensemble en A = ") ; affiche (ens) ;
/* on supprime un eventuel objet de valeur Integer(5) */
Integer cinq = 5;
boolean enleve = [Link] (cinq) ;
if (enleve) [Link] (" On a supprime 5") ;
[Link] ("Ensemble en B = ") ; affiche (ens) ;
/* on teste la presence de Integer(5) */
boolean existe = [Link] (cinq) ;
if (!existe) [Link] (" On ne trouve pas 5") ;}
public static <E> void affiche (HashSet<E> ens)
{ Iterator<E> iter = [Link] () ; while ([Link]())
{ [Link] ([Link]()+ " ") ; } [Link] () ;}}
Université Constantine 2 63
Opérations ensembliste:
• [Link](e2) place dans e1 tous les
éléments présents dans e2. Après
exécution, la réunion de e1 et de e2 se
trouve dans e1 (dont le contenu a
généralement été modifié).
• [Link] (e2) garde dans e1 ce qui
appartient à e2. Après exécution, on obtient
l’intersection de e1 et de e2 dans e1 (dont le
contenu a généralement été modifié).
• [Link] (e2) supprime de e1 tout ce qui
appartient à e2. Après exécution, on obtient le
"complémentaire de e2 par rapport à e1" dans
e1 (dont le contenu a généralement été
modifié).
Université Constantine 2 64
Opérations ensembliste:
• Dès que l’on cherche à utiliser des éléments d’un
autre type objet, il est nécessaire de connaître
quelques conséquences de la manière dont les
ensembles sont effectivement implémentés.
• Dans le cas des HashSet, vous devrez définir
convenablement :
• la méthode equals : c’est toujours elle qui sert à
définir l’appartenance d’un élément à l’ensemble,
• la méthode hashCode pour ordonnancer les
éléments d’un ensemble,
• Table de hachage: organisation des éléments d’une
collection qui permet de retrouver facilement un
élément de valeur donnée.
• on utilise une méthode (hash-Code) dite "fonction de hachage«
Université Constantine 2 65
HachCode: Fonction de hachage
• Fonction de hachage: Associe un entier à la valeur
d’un élément (existant ou recherché),
• Un même entier peut correspondre à plusieurs
valeurs différentes.
• Deux éléments de même valeur doivent toujours
fournir le même code de hachage.
Université Constantine 2 66
HashSet<E>: Construction et parcours
import [Link].* ;
public class EnsPt1 class Point
{ public static void main (String args[]) { Point (int x, int y) { this.x = x ; this.y = y ; }
{ Point p1 = new Point (1, 3), p2 = new Point (2, 2) ; public int hashCode ()
Point p3 = new Point (4, 5), p4 = new Point (1, 8) ; { return x+y ; }
Point p[] = {p1, p2, p1, p3, p4, p3} ; public boolean equals (Object pp)
HashSet<Point> ens = new HashSet<Point> () ; { Point p = (Point) pp ;
for (Point px : p) return ((this.x == p.x) & (this.y == p.y)) ;
{ [Link] ("le point ") ; }
[Link]() ; public void affiche ()
boolean ajoute = [Link] (px) ; { [Link] ("[" + x + " " + y + "] ") ;
if (ajoute) [Link] (" a ete ajoute") ; }
else [Link] ("est deja present") ; private int x, y ;
[Link] ("ensemble = " ) ; affiche(ens) ;}} }
………..
Université Constantine 2 67
HashSet VS ArrayList font
• HashSet et ArrayList font parties des classes les plus importants du framework Java Collection. Ci-dessous
quelques différences entre HashSet et ArrayList.
• Implémentation interne
• ArrayList utilise un tableau pour stocker ses éléments.
• HashSet utilise une hashmap pour son implémentation.
• L'ordre des éléments
• ArrayList garde l'ordre des éléments dont ils sont insérés.
• HashSet ne garde pas l'ordre des éléments.
• Duplication
• ArrayList autorise les valeurs dupliquées.
• HashSet n'autorise pas les valeurs dupliquées.
• Performance
• ArrayList utilise un index pour améliorer les performances par appeler la méthode get(index) pour récupérer un
élément et remove(index) pour supprimer un élément.
• HashSet est completement basée sur les objets et ne propose pas de méthode get.
• Objet Null
• Dans ArrayList, n'importe quel element null est permis.
• HashSet autorise seulement une seule valeur null.
Université Constantine 2 68
Map
• C'est un ensemble de paires, contenant une clé et une
valeur.
• Deux clés ne peuvent être égales au sens de equals.
• Une map est un autre type de collection, qui fait
l’association entre des objets nommés clés et des
objets appelés valeurs. Une map peut avoir des
valeurs en doublon, mais jamais des clés en doublon.
Université Constantine 2 69