Java - Généricité
Université de Nantes
V 1.4 - Novembre 2012
© 2008-2012 Laurent Guérin – Licence CC-BY-NC-SA
Introduction
Java - Généricité ( Université de Nantes - Laurent Guérin ) 1
Introduction …
La notion de "Generics" est apparue
dans "Java 5" ( JDK 1.5 )
JSR 14
"Add Generic Types To The
JavaTM Programming Language"
La généricité permet de définir des classes et des
méthodes génériques, c'est-à-dire avec des
"types paramétrables".
Les caractéristiques génériques d'une
classe/méthode peuvent être utilisées avec
différents types
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 3
Avant Java 5 …
Exemple d'utilisation de "LinkedList"
Afin de bénéficier d'un comportement "générique"
(utilisable avec tous types d'objets) les méthodes
renvoient et utilisent des paramètres de type "Object"
Liste de chaînes de caractères :
LinkedList list = new LinkedList();
[Link]("A");
[Link]("B");
[Link]("C");
String first = (String) [Link]();
String last = (String) [Link]();
Liste d'entiers :
LinkedList list = new LinkedList();
[Link](new Integer(1));
[Link](new Integer(2));
[Link](new Integer(3));
Integer first = (Integer) [Link]();
Integer last = (Integer) [Link]();
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 4
Java - Généricité ( Université de Nantes - Laurent Guérin ) 2
Avant Java 5 …
Contraintes et risques :
"Casting" nécessaire chaque fois que l'on récupère un
élément
String sFirst = (String) [Link]();
Il est possible de stocker des objets de différents
types dans une même liste
LinkedList list = new LinkedList();
[Link](new Integer(1));
[Link]("ABC"); Aucun contrôle !
[Link](new Date());
String sFirst = (String) [Link](); ClassCastException !
En général une liste contient toujours le même
type d'objets ( liste d'employés, de livres,
d'articles, …)
=> Besoin de listes fortement typées
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 5
Avant Java 5 …
Comment obtenir des listes fortement typées ?
En écrivant des classes spécialisées dont les
méthodes ne travaillent qu'avec un seul type
d'objet
=> écrire une classe pour chaque type !
=> écrire N fois la même chose en changeant
uniquement les types !
Idéalement il faudrait pouvoir …
paramétrer le type
définir le type lors de la déclaration de la liste
c'est la généricité apportée par Java 5
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 6
Java - Généricité ( Université de Nantes - Laurent Guérin ) 3
Principe
Cette tasse est
générique ;-)
Typage :
Cup<Tea> Cup of Tea FORT
Cup<Coffee> Cup of Coffee
Cup<?> Cup of anything FAIBLE
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 7
C'est aussi simple ?
Le principe est simple en apparence,
mais la généricité Java comporte de
nombreuses subtilités.
Le sujet est assez
vaste pour y
consacrer un livre …
( 280 pages ! )
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 8
Java - Généricité ( Université de Nantes - Laurent Guérin ) 4
Utilisation de classes
(ou interfaces) génériques
Les classes génériques de Java 5
Java 5 fourni un certain nombre de classes et
interfaces génériques prêtes à l'emploi
Collections :
Collection, List, Queue, Stack, Dictionary,
ArrayList, Vector, LinkedList,
Set, EnumSet, SortedSet, HashSet, TreeSet,
Map, EnumMap, Hashtable, HashMap, TreeMap,
Iterator, Comparator,
etc …
Mais aussi :
[Link] :
Class, ThreadLocal, Comparable, Iterable
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 10
Java - Généricité ( Université de Nantes - Laurent Guérin ) 5
Quoi de neuf avec la généricité ?
Le contrôle de type
Exemple d'utilisation avec LinkedList …
Type des objets stockés dans la liste
LinkedList<Integer> list = new LinkedList<Integer>();
[Link](new Integer(1));
[Link](new Integer(2));
//[Link]("ABC"); // erreur de compilation
[Link](new Integer(3)); Type contrôlé
par le compilateur
Integer first = [Link]();
Plus de cast (Integer) Très proche
des "templates"
en C++
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 11
Quoi de neuf avec la généricité ?
Du nouveau dans la Javadoc …
NomClasse<E>
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 12
Java - Généricité ( Université de Nantes - Laurent Guérin ) 6
Quoi de neuf avec la généricité ?
Notion de "paramètre de type"
Un paramètre de type est noté entre "<" et ">"
Il est utilisé pour définir une classe générique
ou une interface générique.
Exemples :
LinkedList<E> "classe générique"
ou "classe paramétrée"
List<E> "interface générique"
ou "interface paramétrée"
Dans ces deux exemples, E est appelé
"paramètre de type formel" ( ou "paramètre de type" )
"variable de type"
Utilisation d'une classe générique LinkedList<Integer> l;
=> renseigner le paramètre de type Collection<String> c;
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 13
Types primitifs et objets ( "wrappers" )
Les types primitifs ne sont pas supportés
LinkedList<int>
Erreur !
LinkedList<double>
Seuls les "objets" sont utilisables comme
paramètre de type
LinkedList<String>
LinkedList<Date>
LinkedList<Boolean>
LinkedList<Class>
LinkedList<Object>
OK
LinkedList<int[]> Les tableaux
LinkedList<double[]> de types primitifs
sont des objets
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 14
Java - Généricité ( Université de Nantes - Laurent Guérin ) 7
Types primitifs et objets ( "wrappers" )
Type primitif Wrapper
Rappel … ( valeur ) ( référence )
byte Byte
short Short
int Integer
long Long
float Float
boolean Boolean
char Character
Conversion
float Float « boxing »
float Float « unboxing »
« Autoboxing » : conversion automatique (Java 5+)
La généricité réalise les conversions automatiques
( autoboxing ) lorsque c’est nécessaire.
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 15
Portabilité ascendante
La portabilité du code Java 1.4 est garantie
Les règles de typage n'ont pas changé
De nouveaux types sont apparus, avec de
nouvelles règles pour définir le sous-typage
Avec un compilateur Java 5, l'absence de
type (code Java 1.4) provoque un warning :
LinkedList is a raw type. References to generic type LinkedList<E> should be parameterized
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 16
Java - Généricité ( Université de Nantes - Laurent Guérin ) 8
Exemples d'utilisation
Déclaration & instanciation
Déclaration :
Préciser un type concret (ou « ? »)
pour chaque « paramètre de type »
cf Javadoc + complétion de l’environnement
de développement
Instanciation :
Créer une instance compatible avec la classe ou
l’interface et avec le/les type(s) paramétré(s)
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 18
Java - Généricité ( Université de Nantes - Laurent Guérin ) 9
Déclaration & instanciation
Exemples :
List<String> list = new LinkedList<String>();
Box<Integer> integerBox = new Box<Integer>();
List<Student> list = new ArrayList<Student>();
Map<String, List<String>> table =
new Hashmap<String,List<String>>();
NB :
Cannot instantiate the type LinkedList<?>
new LinkedList<?>(); // Erreur
L’instanciation nécessite
new LinkedList<Object>(); // OK
un type explicite
LinkedList<?> list = new LinkedList<Object>(); // OK
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 19
Java 7 : « Diamond Operator »
Java est en évolution
permanente…
L’une des nouveautés
de Java SE 7 (code « Dolphin », Juillet 2011)
est l’opérateur <> qui permet d’éviter de
répéter le type paramétré
Exemples : The Diamond
List<String> list = new LinkedList<>();
Box<Integer> integerBox = new Box<>();
List<?> list = new ArrayList<>();
Map<String, List<String>> table = new Hashmap<>(); "Type
Inference"
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 20
Java - Généricité ( Université de Nantes - Laurent Guérin ) 10
Utiliser une classe/interface générique
public static List<String> getList() {
return new LinkedList<String>();
}
public static void populateStrList( List<String> list ) {
for ( int i = 0 ; i < 5 ; i++ ) { Avec généricité
[Link]("item " + i);
}
}
public static void printStrList( List<String> list ) {
for ( String item : list ) {
[Link](" . " + item );
}
}
public static void printList( List list ) {
for ( Object item : list ) {
[Link](" . " + item ); Sans généricité
}
}
List<String> list = getList();
populateStrList(list);
printStrList(list);
printList(list); // Sans généricité
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 21
Implémenter une interface générique
public class Personne implements Comparable<Personne> {
private String nom; Interface
private String prenom; générique
public Personne(String nom, String prenom) { avec type Personne
[Link] = nom;
[Link] = prenom;
}
public int compareTo(Personne personne) {
int result = [Link]([Link]);
return result == 0 ? [Link]([Link]) : result;
}
On ne peut plus avoir de
}
méthode compareTo(Object o)
public class Personne implements Comparable {
.. .. .. Interface
public int compareTo(Object obj) { générique
if ( obj instanceof Personne ) { sans type
Personne personne = (Personne) obj ;
int result = [Link]([Link]);
return result == 0 ? [Link]([Link]) : result;
}
return 0;
}
}
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 22
Java - Généricité ( Université de Nantes - Laurent Guérin ) 11
Généricité et héritage
Généricité et héritage
Soit les 3 classes suivantes :
Animal
Chien Chat
Ce qui est possible avec des tableaux …
Chat[] chats = new Chat[10];
Animal[] animaux = chats ;
ne l'est pas avec des listes génériques !
LinkedList<Chat> listChats = new LinkedList<Chat>();
LinkedList<Animal> listAnimaux = listChats; Erreur !
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 24
Java - Généricité ( Université de Nantes - Laurent Guérin ) 12
Généricité et héritage
Il n'y a aucune relation d'héritage entre les
classes génériques utilisant ces trois types
Exemple avec LinkedList :
LinkedList<Animal>
LinkedList<Chien> 3 listes d'un type donné
LinkedList<Chat>
Les types ont une
relation d'héritage,
mais pas les listes !
LinkedList<Animal>
LinkedList<Chien> LinkedList<Chat>
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 25
Généricité et héritage
Exemple de code :
public static void afficher( LinkedList<Animal> list ) {
for ( Animal i : list )
{
[Link](" . " + i);
}
}
public static void fct()
{
LinkedList<Animal> listAnimal = new LinkedList<Animal>();
LinkedList<Chat> listChat = new LinkedList<Chat>();
LinkedList<Chien> listChien = new LinkedList<Chien>();
listAnimal = listChat ;
listAnimal = listChien ; Erreur !
LinkedList<Chat>
afficher(listAnimal);
OK n'est pas un sous-type
de LinkedList<Animal>
afficher(listChat); Erreur !
}
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 26
Java - Généricité ( Université de Nantes - Laurent Guérin ) 13
Généricité et héritage
Ces restrictions permettent de protéger
l'intégrité des listes
Sans cela, le code ci-dessous compilerait :
LinkedList<Animal> listAnimal ;
LinkedList<Chat> listChat = new LinkedList<Chat>();
[Link]( new Chat("Felix") );
listAnimal = listChat ;
[Link]( new Chien("Medor") );
Ce qui permettrait d'ajouter une instance
de "Chien" dans une liste de "Chat" !
NB : Les listes non typées restent utilisables
LinkedList<Chat> listChat = new LinkedList<Chat>();
[Link]( new Chat("Felix") );
LinkedList list = listChat ; Simple warning
[Link]( new Chien("Medor") );
du compilateur !
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 27
Généricité et héritage
Les relations d'héritage entre classes génériques
sont évidemment conservées
Exemple : LinkedList et Vector implémentent
l'interface List ( ce sont des sous-types de List )
List
donc …
LinkedList Vector List<Chat>
LinkedList<Chat> Vector<Chat>
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 28
Java - Généricité ( Université de Nantes - Laurent Guérin ) 14
Généricité et héritage
Exemple d'héritage entre classes génériques :
LinkedList<Chat> linkedList = new LinkedList<Chat>();
Vector<Chat> vector = new Vector<Chat>();
ArrayList<Chat> arrayList = new ArrayList<Chat>();
List<Chat> list = null ;
list = linkedList ; Héritage respecté
list = vector ; OK et types compatibles
list = arrayList ;
LinkedList<Chien> linkedListChien = new LinkedList<Chien>();
list = linkedListChien ;
Erreur ! Héritage respecté
mais types incompatibles
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 29
Utilisation du "joker" ( "wildcard" )
L'absence d'héritage au niveau des types nuit à
la réutilisation de méthodes. Exemple :
afficherAnimaux ( LinkedList<Animal> list )
afficherChats ( LinkedList<Chat> list )
etc …
Le principe d'instanciation de type générique
avec joker ("wildcard instanciation") a été ajouté
pour supprimer cette contrainte
Il permet d'utiliser "?" comme "joker" pour
désigner un type générique
Ce "joker" peut être utilisé avec ou sans
contraintes d'héritage ( "extends" et "super" )
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 30
Java - Généricité ( Université de Nantes - Laurent Guérin ) 15
"joker" et types génériques
Exemples :
public static void afficher( LinkedList<?> list ) {
for ( Object i : list ) { Type :
[Link](" . " + i);
}
quelconque
}
public static void afficherAnimaux(
LinkedList<? extends Animal> list) {
for ( Animal i : list ) {
[Link](" . " + i); Type : Animal ou
} sous-type de Animal
} ( Chat, Chien )
public static void afficherSuper(
LinkedList<? super Animal> list) {
for ( Object i : list ) {
[Link](" . " + i); Type : Animal ou
} sur-type de Animal
} ( Object )
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 31
"joker" et héritage avec "extends"
Héritage "limité vers le haut" ( limite = Animal ) :
« upper bound »
LinkedList
LinkedList<?>
« bounded
LinkedList< ? extends Animal > type »
LinkedList<Animal> LinkedList<Chat> LinkedList<Chien>
Le type lui-même … et tous ses sous-types
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 32
Java - Généricité ( Université de Nantes - Laurent Guérin ) 16
"joker" et héritage avec "extends"
Exemples :
List<? extends Number> listNumber = new LinkedList<Integer>() ;
List<? extends Animal> list1 = new LinkedList<Animal>() ;
List<? extends Animal> list2 = new LinkedList<Chat>() ;
List<? extends Comparable> list5 = new LinkedList<Integer>() ;
List<? extends Comparable> list6 = new LinkedList<String>() ;
Comparable = interface
public static void printNumList( List<? extends Number> list ) {
for ( Number item : list )
{
[Link](" . " + item );
}
}
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 33
"joker" et héritage avec "super"
Héritage "limité vers le bas" ( limite = Animal ) :
« lower bound »
LinkedList
LinkedList<?>
« bounded
LinkedList< ? super Animal > type »
LinkedList<Animal> LinkedList<Object>
Le type lui-même … et tous ses sur-types
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 34
Java - Généricité ( Université de Nantes - Laurent Guérin ) 17
"joker" et héritage avec "super"
Exemples :
List<? super Animal> list1 = new LinkedList<Animal>() ;
List<? super Animal> list2 = new LinkedList<Chat>() ; // ERR
List<? super Animal> list3 = new LinkedList<Object>() ;
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 35
Utilisation des types avec "joker"
Utilisations possibles :
Pour déclarer des variables, des paramètres, des types
de retour :
List<? extends Number> listNumber = new LinkedList<Integer>() ;
LinkedList<?> list = null ;
Utilisations impossibles :
Pour instancier un objet :
List<? extends Integer> l = new LinkedList<? extends Integer>() ;
List<? extends Integer> listes [] =
new LinkedList<? extends Integer> [12] ;
Pour déclarer une variable ou un paramètre :
<? extends Integer> item = [Link](2); Doit être précédé
void add (<? extends Integer> param ) d'un nom de classe !
En tant que super type :
class MyClass<T> implements Comparable< ? extends T >
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 36
Java - Généricité ( Université de Nantes - Laurent Guérin ) 18
Warnings du compilateur
Castings & warnings
public static LinkedList<?> getList(String file) {
if ( "file1".equals ( file ) ) {
LinkedList<String> list = new LinkedList<String>();
[Link]("AAA");
[Link]("BBB");
return list ;
}
else if ( "file2".equals ( file ) ) {
LinkedList<Integer> list = new LinkedList<Integer>();
[Link](10);
[Link](20);
return list ;
}
return null ;
}
LinkedList<? extends Object> list1 = getList("myfile1"); OK
LinkedList<?> list2 = getList("myfile2"); OK
LinkedList<String> list3 = (LinkedList<String>) getList("myfile3");
Warning
Type safety : Unchecked cast from LinkedList<capture#3-of ?> to LinkedList<String>
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 38
Java - Généricité ( Université de Nantes - Laurent Guérin ) 19
Utilisation de « jar » sans généricité
[Link] // Avec généricité
public class NewList<T> {
Application public List<T> getItems() { … }
(Java 5+) }
(Java 5+)
[Link] // Sans généricité !
public class OldList {
public List getItems() { … }
(Java 1.4) }
NewList<String> newlist = new NewList<String>();
List<String> items = [Link](); // OK
OldList oldlist = new OldList();
List<?> items1 = [Link](); // OK ( mais pas de typage )
Type safety : The expression of type
List needs unchecked
List<String> items1 = [Link]();
conversion to conform to List<String>
@SuppressWarnings("unchecked") Suppression du warning par annotation
List<String> items2 = [Link](); // OK
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 39
Principe de fonctionnement
Java - Généricité ( Université de Nantes - Laurent Guérin ) 20
Fonctionnement
Contrairement aux "templates" de C++, les
différentes instanciations de types génériques ne
produisent qu'un seul type : le type "raw"
Exemple :
LinkedList<Integer> JVM
"raw
LinkedList<Chat> type"
LinkedList
LinkedList<Chien>
La principale contrainte définie pour la mise en
ouvre de la généricité était la portabilité du code
antérieur à Java 5.
Solution retenue : "effacement de type"
( "type erasure " )
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 41
Fonctionnement
En Java la généricité repose sur le compilateur
C'est le compilateur qui fait tous les contrôles de
compatibilité de type.
Le compilateur retire toute trace de typage au
niveau du "byte code" qui est ainsi semblable à
du byte code antérieur à Java 5.
Conserve
source byte code uniquement
.java compilateur .class la liste des
types
avec type sans paramétrés
typage fort erasure typage
LinkedList<Integer> LinkedList<E>
Hashtable<Short, String> Hashtable<K,V> « raw type »
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 42
Java - Généricité ( Université de Nantes - Laurent Guérin ) 21
Effacement de type …
Très critiqué
Point noir de la généricité ?
Induit des contraintes !
Certaines erreurs de
compilations, certains
comportements, ne peuvent
être compris qu'en gardant
à l'esprit le principe
d'effacement de type
Eric Burke
[Link]
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 43
Contraintes liées à l'effacement de type
Exemple : récupération de classe :
List<String> list1 = new LinkedList<String>();
List<Long> list2 = new LinkedList<Long>();
if ( [Link]().equals( [Link]() ) ) true
[Link]("Meme classe");
else Une seule et même classe :
[Link]("Classes différentes"); [Link]
( "raw type" )
Incohérences :
Object obj = new LinkedList<Long>();
if ( obj instanceof List ) OK
if ( obj instanceof List<?> )
if ( obj instanceof List<Long> )
if ( obj instanceof List<? extends Number> ) Erreur
if ( obj instanceof List<? super Number> )
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 44
Java - Généricité ( Université de Nantes - Laurent Guérin ) 22
Contraintes liées à l'effacement de type
Les types paramétrés ne permettent pas de
définir une nouvelle signature de méthode
public void afficher ( LinkedList<Animal> list ) {
}
public void afficher ( LinkedList<Integer> list ) {
}
Erreur : Duplicate method
Il n'est pas possible d'utiliser "instanceof" sur
un type paramétré
public void afficher ( LinkedList<? extends Animal> list ) {
if ( list instanceof LinkedList<Chat> ) {
}
} Erreur : Cannot perform instanceof ...
since generic type information will be erased at runtime
Cas particulier : instanceof LinkedList<?> est autorisé
(équivalent à intanceof LinkedList (« raw type » )
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 45
Contraintes liées à l'effacement de type
Tableaux de classes génériques :
LinkedList<Integer> lists[] = new LinkedList<Integer> [10] ;
Erreur : Cannot create a generic array of LinkedList<Integer>
LinkedList<Integer> lists[] = new LinkedList<?> [10] ;
Erreur : Type mismatch : cannot convert from LinkedList<?>[] to LinkedList<Integer>[]
LinkedList<Integer> lists[] = ( LinkedList<Integer>[] )
new LinkedList<?> [10] ;
Warning : Type safety : Unchecked cast from LinkedList<?>[] to LinkedList<Integer>[]
LinkedList<?> lists[] = new LinkedList<?> [10] ;
OK , mais pas de typage fort
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 46
Java - Généricité ( Université de Nantes - Laurent Guérin ) 23
Créer des classes génériques
Classe générique
Une classe "normale" ne devient pas "générique"
par le simple fait d'ajouter un paramètre de type
lors de son utilisation.
MaClasse MaClasse c; // OK
(non générique) MaClasse<String> c; // ERREUR
Une classe est générique si elle a été définie
comme telle, en utilisant au moins un
"paramètre de type" lors de son codage.
Exemple …
public class MyGeneric<Type> {
// définition des variables et des méthodes
}
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 48
Java - Généricité ( Université de Nantes - Laurent Guérin ) 24
Définition d'une classe générique
Paramètre de
package [Link] ; type formel
( entre < et > )
public class MyGeneric<Type> => Classe générique
{
private Type val = null ; Le nom du type n'a
aucune importance
public Type get() { ( = nom de paramètre )
return val;
}
Utilisation du
public void set(Type s) { type formel
[Link] = s; comme s'il
} s'agissait d'un
type "normal"
@Override
public String toString() { NB : sans < >
return [Link]() ;
}
} Le nom du type est un nom symbolique,
et non une classe concrète, donc :
new Type() impossible
[Link] impossible
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 49
Utilisation d'une classe générique
public static void main(String[] args) {
MyGeneric<String> gs = new MyGeneric<String>(); Instance
[Link]("aaaa"); dédiée
//[Link](new Integer(1) ); // Erreur de compil. au type
[Link](" gs : " + gs ); String
[Link]("bbbb");
[Link](" gs : " + gs );
MyGeneric<Integer> gi = new MyGeneric<Integer>();
Instance
[Link](new Integer(1));
dédiée
[Link](" gi : " + gi );
au type
[Link](new Integer(56));
Integer
[Link](" gi : " + gi );
MyGeneric g = new MyGeneric() ;
[Link]("aaa"); Instance non typée.
[Link](new Integer(1)); Utilisable,
[Link](" g : " + g ); mais warning !
} Modif : "References to generic type MyGeneric<Type>
MyGeneric<Object> g = should be parameterized"
new MyGeneric<Object>() ;
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 50
Java - Généricité ( Université de Nantes - Laurent Guérin ) 25
Classe générique avec plusieurs types
public class MyGeneric<Type1, Type2> {
private Type1 key = null ;
2 paramètres
private Type2 val = null ;
de type
public MyGeneric2(Type1 k, Type2 v) {
( entre < et >
super();
[Link] = k; séparés par , )
[Link] = v;
}
public Type1 getKey() { Pour N paramètres
return key ; de type :
} < T1, T2, …., Tn >
public Type2 getVal() {
return val ;
}
public void set(Type1 k, Type2 v) {
[Link] = k;
[Link] = v;
}
public String toString() {
return [Link]() + ":" + [Link]();
}
}
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 51
Classe générique avec héritage
public class MyList<T> extends LinkedList<T> {
@Override Classe générique
public boolean add(T o) { qui étend une
[Link]("add()..."); classe générique
return [Link](o); ( et surcharge
} 2 méthodes )
@Override
public T get(int index) {
[Link]("get("+ index + ")...");
return [Link](index);
}
}
public class MyBooks extends LinkedList<Book> {
Classe non générique
... qui étend une
... Un type doit classe générique
} être précisé
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 52
Java - Généricité ( Université de Nantes - Laurent Guérin ) 26
Commentaires "Javadoc"
La classe a des paramètres (paramètres de type)
=> ces paramètres sont décrits au niveau du
bloc de commentaire de la classe
/**
* @param <Type1> the type of the key paramètres
* @param <Type2> the type of the value "de classe"
*/
public class MyGeneric2<Type1, Type2> {
private Type1 key = null ;
private Type2 val = null ;
/**
paramètres
* @param k
"de méthode"
* @param v
( pas de changement )
*/
public MyGeneric2(Type1 k, Type2 v) {
super();
[Link] = k;
[Link] = v;
}
}
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 53
Créer des
méthodes génériques
Java - Généricité ( Université de Nantes - Laurent Guérin ) 27
Méthodes génériques
Il est possible de créer des méthodes
génériques dans n'importe quel type de
classe …
dans des classes standards (non génériques)
dans des classes génériques
Il suffit de préfixer la méthode par le (ou les)
paramètre(s) de type …
lors de sa définition
lors de son utilisation (non obligatoire, mais conseillé)
Le type paramétré est applicable uniquement
à la méthode (et non à la classe)
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 55
Méthodes génériques
Exemple : classe non générique,
mais avec une méthode générique
// Classe standard ( sans type paramétré )
public class Util
{
// Methode standard ( sans type paramétré )
public void setIfNull( Object[] array, Object item, int i )
{
if ( array[i] == null )
{
array[i] = item ; // si types différents : erreur
}
}
// Methode générique ( avec type paramétrée )
public <T> void genericSetIfNull( T[] array, T item, int i )
{
if ( array[i] == null )
{
array[i] = item ; // forcément du même type
}
Rappel :
}
après "effacement de type"
}
les méthodes ont la même signature
=> les noms doivent être différents
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 56
Java - Généricité ( Université de Nantes - Laurent Guérin ) 28
Appel de méthodes génériques
Appel de méthode non générique
Util util = new Util();
String[] chiffres = {"zero", "un", null, "trois", null};
[Link](chiffres, "DEUX", 2 ); OK
[Link](chiffres, new Integer(2), 2 ); ArrayStoreException
Appel de méthode générique, en indiquant le type
util.<String>genericSetIfNull(chiffres, "DEUX", 2 ); OK
util.<String>genericSetIfNull(chiffres, new Integer(2), 2 );
Erreur de compilation
The parameterized method ... is not applicable for the arguments ...
Appel de méthode générique, sans indiquer le type
=> "inférence de type" (le compilateur tente de "deviner" le type)
[Link](chiffres, "DEUX", 2 ); OK
Interprétation du compilateur :
<String> genericSetIfNull ( String[] , String , int )
[Link](chiffres, new Integer(2), 2 ); ArrayStoreException
Interprétation du compilateur :
<? extends Object> genericSetIfNull (? extends Object [] , ? extends Object , int )
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 57
Méthodes génériques
Exemple : une méthode de recherche qui
renvoie un objet d’une classe passée en
paramètre ( permet un appel sans « cast » )
public class Finder {
// Le type de retour est le même que la classe passée
// en paramètre
public <T> T find(Class<T> entityClass, String name) {
// Find Rappel : il n’est pas possible de connaitre la
return instance ; classe du type paramétré.
} Pour contourner cette limite il suffit de passer
} la classe en paramètre
Finder finder = new Finder();
// Le type de retour est connu => Pas de “cast”
Personne p = [Link]([Link], "Toto");
[Link]( " Personne : " + p );
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 58
Java - Généricité ( Université de Nantes - Laurent Guérin ) 29
Méthodes génériques
un peu plus loin avec les types …
public <T extends Comparable<T>> void sort(List<T> list) {
Object a[] = [Link](); Un type "Comparable"
[Link](a); // must be Comparable ou ses descendants
for(int i=0; i < [Link]; i++) {
[Link](i, (T)a[i]);
}
}
List<String> list = new LinkedList<String>();
[Link]("zzzz");
[Link]("ccc");
sort(list); // OK ( String implémente "Comparable" )
List<Trio> lt = new LinkedList<Trio>();
[Link]( new Trio<String>("aa", "bb", "cc") );
sort(lt); // Erreur ( car Trio n'implémente pas "Comparable" )
encore plus loin …
public <T extends Comparable<? super T>> void sort(List<T> l) {
.. ..
}
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 59
Méthodes génériques du JDK
JPA (Java Persistance API) / EntityManager
public <T> T find( Class<T> entityClass, Object primaryKey )
public <T> T merge( T entity )
Framework Spring / BeanFactory
public <T> T getBean( Class<T> beanClass )
public <T> T getBean( String name, Class<T> beanClass )
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 60
Java - Généricité ( Université de Nantes - Laurent Guérin ) 30
Les classes et la généricité
Classes et généricité
Une instance de "[Link]" contient la
description de la classe Java d'un objet donné
(objet quelconque).
Class c = [Link]() ; // Classe d'une instance
Class c = [Link] ; // Classe de la classe "Integer"
Depuis Java 5, la classe "Class" est générique
=> on peut contraindre le type d'objet
Class<Integer> c3 = [Link] ; // OK
Class<Integer> c1 = [Link] ; // Erreur
Class<Integer> c2 = [Link] ; // Erreur
Class<Number> c4 = [Link] ; // Erreur (pas d'héritage)
Class<? extends Number> c5 = [Link] // OK
Integer i = new Integer(123); Signature :
Class c1 = [Link](); Class<? extends Integer> [Link]()
StringBuffer sb = new StringBuffer();
Class c2 = [Link](); Signature :
Class<? extends StringBuffer> [Link]()
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 62
Java - Généricité ( Université de Nantes - Laurent Guérin ) 31
Classes et généricité
Exemple sans généricité
public static List creerAnimaux( Class cl ) {
LinkedList list = new LinkedList();
try {
for ( int i = 0 ; i < 10 ; i++ ) { N'importe quelle classe
Object o = [Link]();
if ( o instanceof Animal ) {
[Link](o);
}
else {
[Link]("invalid class " + [Link]() ) ;
return list;
}
}
} catch (InstantiationException e) {
[Link]();
} catch (IllegalAccessException e) {
[Link]();
}
return list ;
}
List list = creerAnimaux([Link]) ; // OK
List list = creerAnimaux([Link]) ; // Err dans la méthode
(pas de contrôle à la compilation, erreur à l'exécution car contrôlé dans la méthode)
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 63
Classes et généricité
Utilisation de la classe "Class" avec un type
public static List<Animal> creerAnimauxGen( Class<? extends Animal> cl)
{
LinkedList<Animal> list = new LinkedList<Animal>();
try {
for ( int i = 0 ; i < 5 ; i++ ) { Classe qui
Animal o = [Link](); étend Animal
[Link](o);
}
} catch (InstantiationException e) {
[Link]();
} catch (IllegalAccessException e) {
[Link]();
}
return list ;
}
List<Animal> chats = creerAnimauxGen([Link]) ; // OK
List<Animal> chiens = creerAnimauxGen([Link]) ; // OK
List<Animal> animaux = creerAnimauxGen([Link]) ; // Runtime error
( car Animal est une classe abstraite )
List<Animal> list = creerAnimauxGen([Link]) ; // Compil error
Java - Généricité ( Laurent Guérin / ver 1.4 / [Link] ) 64
Java - Généricité ( Université de Nantes - Laurent Guérin ) 32
FIN
Java - Généricité ( Université de Nantes - Laurent Guérin ) 33