Généricité (Polymorphisme paramétrique) en Java

O'Reilly Media
Page 1 sur 29Lecteur de document UniversityLib

Généricité (Polymorphisme paramétrique) en Java

Computer Science, Java Programming · notes

Browse all programmation documents

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

Advertisement

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;

Advertisement

}

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{

Advertisement

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>

Advertisement

<<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