G n ricit
(polymorphisme param trique)
en Java
Philippe GENOUD
UJF
Janvier 2015
1
G n ricit Motivations
" 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
&
" Comment proc der ?
Philippe GENOUD
UJF
Janvier 2015
2
G n ricit Motivations
" 1 re solution : crire une classe pour chaque type de valeur que l'on
peut mettre dans la file
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;
}
}
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;
}
}
Philippe GENOUD
UJF
Janvier 2015
3
G n ricit Motivation
" 1 re solution : crire une classe pour chaque type de valeur que l'on
peut mettre dans la file
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 Personne retirer() {
Personne val = null;
if (!estVide()) {
val = t te.getValue();
t te = t te.getNext();
}
return val;
}
}
class ElementPersonne {
private final Personne value;
private ElementPersonne next;
ElementPersonne(Personne val) {
this.value = val;
next = null;
}
void inserer(ElementPersonne elt) {
this.next = elt;
}
Personne getValue() {
return value;
}
ElementPersonne getNext() {
return next;
}
}
" 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
Philippe GENOUD
UJF
Janvier 2015
4
G n ricit Motivation
" 2 me solution : utiliser un type "universel", Object en Java
toute classe h ritant de Object il est possible d'utiliser FileAttente pour
stocker n'importe quel type d'objet
class Element {
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;
}
}
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;
}
}
une file d'attente
de personnes
une file d'attente
d' v nements
FileAttente f1 = new FileAttente();
f1.add(new Personne(...));
FileAttente f2 = new FileAttente();
f2.add(new Event(...));
Philippe GENOUD
UJF
Janvier 2015
5
G n ricit
Motivation
" Mais ...
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 = f1.retirer() .getNom();
(Personne)( )
Transtypage
Object
l obligation pour le programmeur
d'effectuer un transtypage lorsquil
acc de aux l ments de la file d'attente
f1.ajouter("Hello");
String nom = (Personne) (f1.retirer()).getNom();
l pas de contr le sur les valeurs
rang es dans la file d'attente
ClassCastException
code lourd, moins lisible, plus difficile maintenir
risques derreurs dex cution.
Philippe GENOUD
UJF
Janvier 2015
6
G n ricit
Motivation
" Mais ...
Mais a, c' tait avant&
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 = f1.retirer() .getNom();
(Personne)( )
l obligation pour le programmeur
d'effectuer un transtypage lorsquil
acc de aux l ments de la file d'attente
Transtypage
Object
f1.ajouter("Hello");
String nom = (Personne) (f1.retirer()).getNom();
l pas de contr le sur les valeurs
rang es dans la file d'attente
ClassCastException
code lourd, moins lisible, plus difficile maintenir
risques derreurs dex cution.
depuis la version 1.5 de java (Tiger)
cela nest quun mauvais souvenir
Publicité
gr ce lintroduction (enfin !) de
la g n ricit dans le langage Java.
Philippe GENOUD
UJF
Janvier 2015
7
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.
dans l'exemple pr c dent le type des l ments serait un
param tre des classes FileAttente et Element
" 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
Element
T
-value : T
Element(val : T)
getValue() : T
getNext() : Element<T>
- next
0..1
Philippe GENOUD
UJF
Janvier 2015
8
G n ricit Exemple
D claration d'une classe
g n rique simple
Les classes Element et FileAttente sont param tr es en fonction dun 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.
public class FileAttente {
<T> {
private Element t te = null;
private Element queue = null;
<T>
4
<T>
param tre de type :repr sente un type inconnu au
moment de la compilation
3
T
<T>
public void ajouter(Object val) {
Element elt = new Element (val);
if (estVide()) {
t te = queue = elt;
} else {
queue.inserer(elt);
queue = elt;
}
}
<T>
4
Dans le code du type
g n rique, le param tre de
type peut tre utilis
comme les autres types :
public boolean estVide() {
return t te == null;
}
pour d clarer des variables
class Element {
<T> {
<T> {
private final Object value;
private Element next;
T
1
3
T
Element(Object val) {
this.value = val;
next = null;
}
void inserer(Element elt) {
1
this.next = elt;
}
4
<T>
2
1
T
public Object retirer() {
T
Object val = null;
if (!estVide()) {
val = t te.getValue();
t te = t te.getNext();
}
return val;
}
}
pour d finir le type de
retour ou le type des
param tres de m thodes
2
2
public Object getValue() {
return value;
}
3
T
comme argument d'autres
types g n riques
4
<T>
public Element getNext() {
return next;
}
}
Philippe GENOUD
UJF
Janvier 2015
9
G n ricit
Lors de linstanciation de FileAttente<T> le type formel T est remplac par un type
(Classe ou Interface) existant
Utilisation d'une classe
g n rique simple
Exemple
le type est pass en argument
une file d'attente
de personnes
FileAttente<Personne> f1 = new FileAttente<Personne>();
f1.add(new Personne(...));
une file d'attente
d' v nements
FileAttente<Event> f2 = new FileAttente<>();
f2.add(new Event(...));
Diamond
on n'est pas
oblig de
mentionner les
arguments de
type dans le
constructeur
sans g n ricit (< JDK 5)
avec g n ricit (JDK 5+)
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 = f1.retirer() .getNom();
(Personne)( )
Transtypage obligatoire
f1.ajouter("Hello");
String nom = (Personne) (f1.retirer()).getNom();
ClassCastException
Erreur lex cution
f1.ajouter(new Personne(...));
...
// on veut r cup rer le nom de la personne
// en t te de file.
String nom = f1.retirer().getNom();
Plus de transtypage
Erreur d tect e d s la compilation
f1.ajouter("Hello");
String nom = f1.retirer().getNom();
Type incorrect
La g n ricit simplifie la programmation, vite de dupliquer du code
et le rend plus robuste
Philippe GENOUD
UJF
Janvier 2015
10
G n ricit Types G n riques
Simples
Cas g n ral
"
Type g n rique : Classe ou interface param tr e par un ou plusieurs types
classe g n rique deux param tres
interface g n rique
public interface Comparable<T> {
int compareTo(T o);
}
T - the type of
objects that this
object may be
compared to
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; }
public T2 getSecond() { return second; }
}
"
Instanciation (ou 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)
des interfaces
Paire<String, Forme> c1 = new Paire<>("Cercle 1",new Cercle(0,0,10));
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;
...
Philippe GENOUD
UJF
Janvier 2015
11
G n ricit Compilation de code g n rique
" compilation de code g n rique bas e sur le m canisme d'effacement (erasure)
public class Paire<T1,T2> {
private final T1 first;
private final T2 second;
toutes les informations
de type plac es entre
chevrons sont effac es
public class Paire {
private final Object first;
private final Object second;
public Paire(T1 first, T2 second) {
this.first = first;
this.second = second;
Publicité
}
public T1 getFirst() {
return first;
}
public T2 getSecond() {
return second;
}
}
Les variables de type
sont remplac es par
Object (en fait leur
borne sup rieure en
cas de g n ricit
contrainte)
javac
public PaireO(Object first, Object second) {
this.first = first;
this.second = second;
}
public Object getFirst() {
return first;
}
public Object getSecond() {
return second;
}
}
Le type Paire<T1,T2> a t
remplac par un type brut (raw type)
en substituant Object T1 et T2
insertion d'op rations de
transtypage si n cessaire
javac
String s = (String) c1.getFirst();
Paire.class
Paire<String, String> c1;
c1 = new Paire<>("Hello","World");
String s = c1.getFirst();
Personne p = c1.getFirst();
rejet d s la compilation : une String
n'est pas une Personne
Philippe GENOUD
UJF
Janvier 2015
12
G n ricit cons quences de l'effacement de type
" permet d'assurer la compatibilit ascendante du code.
" l'ex cution, il n'existe qu'une classe (le type brut) partag e par toutes les
instanciations du type g n rique
Paire<String,String> c1;
Paire<Personne,Personne> p1;
c1 = new Paire<>("Hello","World");
p1 = new Paire<>(new Personne("DURAND", "Sophie"),new Personne("DUPONT", "Jean"));
System.out.println( c1.getClass() == p1.getClass() );
true
" mais cela induit un certain nombre de limitations
En C++
cr ation de
code source
sp cifique pour
chaque valeur
de type
les membres statiques d'une classe param tr e sont partag s par toutes les instanciations de
celle-ci
public class Paire<T1,T2> {
private static int nbInstances = 0;
private final T1 first;
private final T2 second;
public Paire(T first, T2 second) {
nbInstances++
this.first = first;
this.second = second;
}
public static getNbInstances() {
return nbInstances;
}
...
Paire<String,String> c1;
Paire<Personne,Personne> p1;
c1 = new Paire<>("Hello","World");
p1 = new Paire<>(new Personne("DURAND", "Sophie"),
new Personne("DUPONT", "Jean"));
System.out.println( Paire.getNbInstances() );
2
Philippe GENOUD
UJF
Janvier 2015
13
G n ricit cons quences de l'effacement de type
" limitations&
les membres statiques d'une classe param tr e ne peuvent 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)
public class C<T> {
T x1;
T[] tab;
static T x2;
erreurs de compilation
T method1(T param) {
...
}
static T method2(T param) {
...
}
void method3(...) {
...
x1 = new T();
tab = new T[10] ;
}
...
}
Philippe GENOUD
UJF
Janvier 2015
14
G n ricit cons quences de l'effacement de type
" limitations&
seul le type brut est connu l'ex cution
Paire<String, String> c1 = new Paire<>("Hello","World");
Paire<String, Personne> p1 = new Paire<>("personne 1", new Personne("DURAND", "Sophie"));
System.out.println( c1.getClass() == p1.getClass() );
System.out.println( c1 instanceof Paire );
System.out.println( c1 instanceof Paire );
on ne peut utiliser un type g n rique instanci dans un contexte de v rification de type
if ( c1 instanceof Paire<String, String>) { ... }
- dans un contexte de coercition de type (transtypage) on pourra avoir une erreur l'ex cution mais
pas n cessairement l o on l'attend&
Object obj = p1;
Paire<String, String> c2 = (Paire<String, String>) obj;
...
System.out.println(c2.getFirst());
ClassCastException: Personne cannot be cast to String
- on ne peut instancier de tableaux d'un type g n rique
Paire<Personne,Personne>[] duos;
duos = new Paire<Personne,Personne>[100] ;
duos = new Paire[100]; // mais utiliser le type brut est possible
duos[0] = p1;
duos[1] = c1;
Philippe GENOUD
UJF
Janvier 2015
15
G n ricit m thodes g n riques
" M thodes g n riques : m thodes qui d finissent leur propres param tres de type.
similaire aux types g n riques mais la port e du param tre de type est limit e la
m thode o il est d clar .
m thodes g n riques peuvent tre d finies dans des types non g n riques
exemple : m thode copyOf de la classe java.util.Arrays
permet de cr er un tableau dune taille donn e qui est une copie dun
tableau pass en param tre
Arrays propose
des m thodes
utilitaires pour
faire de
recherches, tris,
copies de
tableaux&.
T[] un type tableau
int
le m me type tableau que pour original
0
Quelle signature pour cette m thode ?
0
newLength - 1
...
length > newLength
...
length <= newLength
...
length - 1
Tableau
original
newLength - 1
Les autres l ments
sont mis zero
Philippe GENOUD
UJF
Janvier 2015
16
G n ricit
m thodes g n riques
"
d claration de copyOf
Il faut que ces types soient les m mes
public static
TypeTableau
copyOf( original, int newLength)
TypeTableau
Pour les types simples :
surcharge de la m thode
public int[] copyOf(int[] original, int newLength)
public float[] copyOf(float[] original, int newLength)
...
public boolean[] copyOf(boolean[] original, int newLength)
Mais pour les types objets ? Object[] Personne[]
d finition d'une m thode g n rique
T : un type java (classe ou interface)
public static
<T>
T[]
copyOf( original, int newLength)
T[]
Comme pour les classes g n riques, le param tre de type doit tre d clar ,
d claration entre < > avant le type de retour de la m thode
"
invocation d'une m thode g n rique
Personne[] tab1 = new Personne[200];
...
Personne[] tab2 = Arrays.<Personne[]>copyOf(tab1, 100);
Personne[] tab2 = Arrays.copyOf(tab1, 100);
Philippe GENOUD
UJF
Janvier 2015
argument de type
peut tre ignor
l'invocation&
mais attention
on verra plus
tard les cons -
quences
17
G n ricit m thodes g n riques
" Dans l'exemple pr c dent la m thode copyOf est statique, il est aussi possible de
d finir des m thodes non statiques g n riques.
M thode g n rique dans une
classe non g n rique.
M thode g n rique dans une
classe g n rique.
public class Class1{
Publicité
public class Paire<T1, T2> {
private int x;
...
public Class1(...) {
...
}
public <T1,T2> T1 methodX(T1 p1, T2 p2) {
...
}
...
}
teste si la seconde composante de la paire (this) est
gale la seconde composante d'une autre paire
dont la premi re composante n'est pas forc ment
du m me type que celle this
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;
}
public T2 getSecond(){
return second;
}
Le (les) param tre(s) de type de
la m thode g n rique ne fait
(font) pas partie des param tres
de type de la classe.
public <T3> boolean sameScnd(Paire<T1,T3> p) {
return getSecond().equals(p.getSecond());
}
}
Philippe GENOUD
UJF
Janvier 2015
18
G n ricit param trage contraint (ou born )
" Il existe des situations o il peut tre utile d'imposer certaines contraintes sur les
param tre de type (pour une classe, interface ou une m thode g n rique).
" g n ricit contrainte (bounded type parameters)
impose un argument de type d' tre d riv (sous-classe) d'une classe donn e ou d'impl menter
une ou plusieurs interface.
Exemple avec une classe g n rique
public class Couple<T extends Personne> {
private final T first;
private final T second;
public Couple(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() { return first; }
public T getSecond() { return second; }
la classe couple ne pourra tre instanci e qu'avec le
type Personne ou un type d riv
Couple<Personne> cp;
Couple<Etudiant> ce;
Couple<Point> cpt;
erreur de compilation
un point n'est pas une
personne
A la compilation, le m canisme
d'effacement de type consiste
remplacer T par sa borne sup rieure
public class Couple {
type brut (raw type)
private final Personnefirst;
private final Personne second;
public int getAgeMoyen() {
return (first.getAge() + second.getAge()) / 2;
}
}
possibilit d'invoquer les m thodes d finies
dans la borne du type param tr
public Couple(Personne first, Personne second) {
...
}
...
}
ce.getFirst();
(Personne) ce.getFirst();
Philippe GENOUD
UJF
Janvier 2015
19
G n ricit
param trage contraint (ou born )
" borne sup rieure peut tre soit une classe (concr te ou abstraite) soit une interface
<T1 extends T2>
extends est interpr t avec un sens g n ral, si T1 est une
classe et T2 une interface extends doit tre compris
comme implements
" possibilit de d finir des bornes multiples (plusieurs interfaces, une classe et une ou
plusieurs interfaces)
<T extends B1 & B2 & B3>
T est un sous type de tous les types list s et s par s par &
Class A { / ... / }
interface B { / ... / }
interface C { / ... / }
si l'une des bornes est une classe (et il ne peut y en avoir
qu'une seule, car h ritage simple en Java), celle-ci doit tre
sp cifi e en premier
class D <T extends A & B & C> {
...
}
class D <T extends B & 1 & C> {
...
}
A la compilation, le m canisme
d'effacement de type consiste
remplacer T par la premi re de ses
bornes sup rieures (ici A)
Philippe GENOUD
UJF
Janvier 2015
20
G n ricit h ritage de classes g n riques
" Dans l'exemple pr c dent (Couple) n'aurait-il pas t possible de r utiliser le
code de la classe g n rique Paire<T1,T2> ?
public class Paire<T1, T2> {
public class Couple<T extends Personne> {
private final T1 first;
private final T2 second;
private final T first;
private final T second;
public Paire(T1 first, T2 second) {
this.first = first;
this.second = second;
}
public T1 getFirst(){
return first;
}
public T2 getSecond(){
return second;
}
}
public Couple(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() { return first; }
public T getSecond() { return second; }
public int getAgeMoyen() {
return (first.getAge() +
second.getAge()) / 2;
}
}
public class Couple<T extends Personne> extends Paire<T, T> {
Couple(T val1, T val2) {
super(val1, val2);
}
Il est possible de sous typer une classe ou une interface
g n rique en l' tendant ou en l'impl mentant
public int getAgeMoyen() {
return (getFirst().getAge() + getSecond().getAge()) / 2;
}}
Philippe GENOUD
UJF
Janvier 2015
21
G n ricit h ritage de classes g n riques
" diff rentes mani res de d river une classe g n rique
class ClasseA <T> { & }
en conservant les param tres de type
de la classe de base
en ajoutant de nouveaux param tres
de type
en introduisant des contraintes sur un
ou plusieurs des param tres de la
classe de base
en sp cifiant une instance particuli re
de la classe de base
class ClasseB<T> extends ClasseA<T>{
& }
class ClasseB<T,U> extends ClasseA<T>{
& }
class ClasseB<T extends TypeC> extends ClasseA<T>{
& }
class ClasseB extends ClasseA<String>{
& }
class ClasseB<T> extends ClasseA<String>{
& }
" situations incorrectes
l'inverse est possible, une classe g n rique peut h riter d'une classe
non g n rique class ClasseB<T> extends ClasseC{ & }
ClasseB doit disposer au moins du
param tre T
les contraintes doivent tre exprim es
sur les param tre de la classe d riv e
class ClasseB extends ClasseA<T>{
& }
class ClasseB<T> extends ClasseA<T extends TypeC>{
& }
Philippe GENOUD
UJF
Janvier 2015
22
G n ricit h ritage de classes g n riques
" L'API des collections (java.util) s'appuie sur la g n ricit
AbstractCollection<E>
<<interface>>
Iterable<E>
<<interface>>
Collection<E>
AbstractSet<E>
AbstractList<E>
<<interface>>
Set<E>
<<interface>>
Queue<E>
<<interface>>
List<E>
HashSet<E>
LinkedHashSet<E>
AbstractQueue<E>
ArrayList<E>
Vector<E>
AbstractSequentialList<E>
EnumSet<E extends Enum<E>>
<<interface>>
SortedSet<E>
<<interface>>
Deque<E>
LinkedList<E>
PriorityQueue<E>
TreeSet<E>
Publicité
<<interface>>
NavigableSet<E>
ArrayDeque<E>
Philippe GENOUD
UJF
Janvier 2015
23
G n ricit sous-typage
<<interface>>
Collection<E>
<<interface>>
List<E>
LinkedList<E>
ArrayList<E> impl mente List<E>
List<E> tend Collection<E>
Collection<Personne>
ArrayList<Personne> est un sous
type de List<Personne> qui est un sous
type de Collection<Personne>
List<Personne>
ArrayList<Personne>
List<Personne> lesPersonnes = new ArrayList<Personne>();
Personne
Mais qu'en est-il de ArrayList<Etudiant> , est-ce une liste de Personnes ?
List<Personne> lesPersonnes = new ArrayList<Etudiant>();
Etudiant
Enseignant
incompatibles types: ArrayList<Etudiant> cannot be converted to List<Personnes>
supposons que les types soient compatibles : on pourrait crire
List<Etudiant> lesEtudiants = new ArrayList<Etudiant>();
...
List<Personne> lesPersonnes = lesEtudiants;
lesPersonnes.add(new Enseignant("DUPOND","Jean"));
2
1
lesEtudiants
des Etudiants
on pourrait crire ainsi ajouter un enseignant la liste des tudiants
mais alors l'ex cution de
lesEtudiants.get(lesEtudiants.size()-1);
lesPersonnes
add
un Enseignant
donnerait une erreur de transtypage
C'est pourquoi le compilateur interdit l'instruction
2
Philippe GENOUD
UJF
Janvier 2015
24
G n ricit Jokers (wildcards)
" pb: crire une m thode qui affiche tous les l ments d'une collection*
approche na ve
pourquoi cette solution ne
marche t'elle pas ?
Collection<Object>
n'est pas une super classe
de n'importe quel type de
Collection
de mani re g n rale
ClasseA
ClasseG<ClasseA>
ClasseB
ClasseG<ClasseB>
void printCollection(Collection<Object> c) {
for (Object e : c) {
System.out.println(e);
}
}
List<Personne> lesPersonnes = new ArrayList<Personne>();
...
printCollection(lesPersonnes);
incompatibles types: List<Personne> cannot be converted to Collection<Object>
Collection<Personne>
Collection<Object>
List<Personne>
List<Object>
ArrayList<Personne>
ArrayList<Object>
Pourtant il est toujours possible d'utiliser un objet de type ClasseG<ClasseB>
comme un objet de type ClasseG<ClasseA> tant que l'on ne cherche pas
modifier pas sa valeur.
pour offrir cette possibilit les concepteurs de Java ont introduit la
notion de Joker (wildcard)
exemple inspir de : Java tutorial, Lesson Generics de Gilad Bracha https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
Philippe GENOUD
UJF
Janvier 2015
25
G n ricit Joker simple
Quelle supertype pour les types
de collections ?
Collection<?>
???
? : Joker simple
Collection d'un type inconnu
Collection<Object>
Collection<String>
...
Collection<Personne>
" En utilisant un Joker pour typer le param tre Collection de printCollection, il est ensuite
possible d'utiliser cette m thode sur n'importe quel type de collection
void printCollection(Collection<?> c) {
void printCollection(Collection<Object> c) {
for (Object e : c) {
for (Object e : c) {
System.out.println(e);
System.out.println(e);
}
}
}
}
List<Personne> lesPersonnes = new ArrayList<Personne>();
...
printCollection(lesPersonnes);
" Par contre le type des l ments de c tant inconnu, on ne peut lui ajouter des objets
Collection<?> c = new ArrayList<Personne>();
c.add(new Personne("DUPONT", "Jean"));
erreur d tect e la compilation
" De mani re g n rale, ce ne sont pas simplement
les modifications d'un objet de type g n rique
ClasseG<?> qui sont interdites mais tout appel
de m thode recevant un argument de type
correspondant ?
FileAttente<Personne> fp = new FileAttente<>();
Personne p = new Personne("DUPONT", "Jean");
fp.ajouter(p);
FileAttente<?> f = fp;
f.contient(p);
Philippe GENOUD
UJF
Janvier 2015
26
G n ricit jokers avec limitations
" comme pour les param tres de type il est possible d'imposer des restrictions un
joker
" joker avec borne sup rieure <? extends T>
exemple la m thode addAll de Collection<E>
List<Etudiant> lesEtudiants = new ArrayList<>();
...
List<Personne> lesPersonnes = new ArrayList<>();
lesPersonnes.add(new Enseignant("DUPONT","Jean"));
lesPersonnes.add(new Etudiant("DURAND","Anne"));
lesPersonnes.addAll(lesEtudiants);
une collection de n'importe quel type qui
tend le type des l ments de cette collection
comme pour les jokers simples, il n'est pas possible d'invoquer des m thodes ayant un argument
correspondant ? (risques de modifier l'objet de type g n rique avec une valeur dont le type ne
serait pas compatible avec son type effectif)
List<Etudiant> lesEtudiants = new ArrayList<>();
...
List<? Personne> l1 = lesEtudiants;
l1.add(new Etudiant("DURAND","Anne"));
erreur de compilation
Philippe GENOUD
UJF
Janvier 2015
27
G n ricit jokers avec limitations
" joker avec borne inf rieure <? super T>
de la m me mani re qu'un joker avec une borne sup rieure restreint le type inconnu un type
sp cifique ou un sous-type de ce type sp cifique, un joker avec une borne inf rieure restreint le
type inconnu un type sp cifique ou un super type de ce type sp cifique.
exemple: supposons que l'on veuille ajouter la classe Etudiant une m thode qui permet d'ajouter l' tudiant
une liste
Object
Personne
quel type pour uneListe ?
/**
- ajoute cet tudiant une liste
- @param uneListe la liste laquelle cet etudiant est ajout
*/
void ajouterA( uneListe){
List<? super Etudiant>
Il n'est pas possible
de sp cifier
simultan ment une
borne sup rieure et
une borne
inf rieure
Etudiant
Enseignant
uneListe.add(this);
}
une liste peut tre:
" une liste d'Etudiants List<Etudiant>
" une liste de Personnes List<Personne>
" une liste d'objets List<Object>
mais ne peut pas tre une liste d'autre chose
List<String>, List<Enseignant> &
l'inverse des jokers simples ou des jokers avec borne sup rieure, il est possible d'invoquer des m thodes ayant
un argument correspondant la borne inf rieure
(cela ouvre la possibilit de de modifier
l'objet de type g n rique avec une valeur
dont le type correspond la borne
inf rieure). Par contre un transtypage est
n cessaire pour les appels de m thodes
dont le type de retour correspond au joker.
List<Personne> lp = new ArrayList<>();
lp.add(new Personne("DUPONT","Jean"));
lp.add(new Etudiant("DUPOND", "Marcel"));
List<? super Etudiant> l1 = lp;
l1.add(new Etudiant("DURAND", "Anne"));
Personne p = (Personne) l1.get(0);
l1.add(new Personne("DURANT", "Sophie"));
erreur de
compilation
Philippe GENOUD
UJF
Janvier 2015
28
G n ricit r f rences
" The Java Tutorials
Lesson: Generics by Gilad Bracha
https://docs.oracle.com/javase/tutorial/extra/generics/index.html
Lesson: Generics (Updated)
https://docs.oracle.com/javase/tutorial/java/generics/index.html
" Programmer en Java 9 me Edition
Claude Delannoy, Ed. Eyrolles, mai 2014
chapitre 21 : La programmation g n rique
" G n riques et collections Java
Maurice Naftalin et Philip Wadler, Ed OReilly, juillet 2007
Philippe GENOUD
UJF
Janvier 2015
29