Appréhendez La Généricité en Java - Apprenez À Programmer en Java - OpenClassrooms
Appréhendez La Généricité en Java - Apprenez À Programmer en Java - OpenClassrooms
Appréhendez La Généricité en Java - Apprenez À Programmer en Java - OpenClassrooms
Accueil > Cours > Apprenez à programmer en Java > Appréhendez la généricité en Java
Java Orienté
Appréhendez la généricité en Java Objet
Pour assimiler ce concept, ajouté au JDK depuis la version 1.5, nous allons essentiellement 1. Créez votre
travailler avec des exemples tout au long de ce chapitre. Le principe de la généricité est première classe
de faire des classes qui n'acceptent qu'un certain type d'objets ou de données de façon 2. Gérez les héritages
8. Découvrez les
Bon, pour vous montrer la puissance de la généricité, nous allons tout de suite voir un cas énumérations
de classe qui ne l'utilise pas.
9. Créez des
Il existe un exemple très simple que vous pourrez retrouver aisément sur Internet, car il collections d'objets
s'agit d'un des cas les plus faciles permettant d'illustrer les bases de la généricité. Nous 10. Appréhendez la
généricité en Java
allons coder une classe Solo . Celle-ci va travailler avec des références de type String .
Voici le diagramme de classe de cette dernière en gure suivante. 11. Gérez les ux
d'entrée et de sortie
12. Comprenez la
ré exivité
Vous pouvez voir que le code de cette classe est très rudimentaire. On affecte une valeur, références de
méthode
on peut la mettre à jour et la récupérer… Maintenant, si je vous demande de me faire une
classe qui permet de travailler avec n'importe quel type de données, j'ai une vague idée 14. Manipulez vos
de ce que vous allez faire. Ne serait-ce pas quelque chose s'approchant de la gure données avec les
streams
suivante ?
15. Découvrez la
nouvelle API de
gestion des dates
de Java 8
Quiz : Modélisez
J'en étais sûr. Créez la classe Solo , ainsi qu'une classe avec une méthode main . Si vous une solution objet
voulez utiliser les données de l'objet Solo , vous allez devoir faire un cast . Testez ce code Activité : Réalisez
dans votre main : un garage
java
Vous constatez que vous essayez vainement de mettre un objet de type Object dans un
objet de type Integer : c'est interdit ! La classe Object est plus globale que la classe
Integer , vous ne pouvez donc pas effectuer cette opération, sauf si vous castez votre
objet en Integer comme ceci : OpenClassrooms, Leading
Objet générique
Impressionnant, n'est-ce pas ? Dans cette classe, le T n'est pas encore dé ni. Vous vous
en occuperez à l'instanciation de la classe. Par contre, une fois instancié avec un type,
l'objet ne pourra travailler qu'avec le type de données que vous lui avez spéci é ! Exemple
de code :
java
… ou encore ceci :
java
… vous obtiendrez une erreur dans la zone de saisie. Ceci vous indique que votre objet ne
reçoit pas le bon type d'argument, il y a donc un con it entre le type de données que vous
avez passé à votre instance lors de sa création et le type de données que vous essayez
d'utiliser dans celle-ci ! Par contre, vous devez savoir que cette classe ne fonctionne pas
seulement avec des Integer . Vous pouvez utiliser tous les types que vous souhaitez !
Voici une démonstration de ce que j'avance :
java
Vous avez certainement remarqué que je n'ai pas utilisé ici les types de données que vous
employez pour déclarer des variables de type primitif ! Ce sont les classes de ces types
primitifs.
En effet, lorsque vous déclarez une variable de type primitif, vous pouvez utiliser ses
classes enveloppes (on parle aussi de classe wrapper) ; elles ajoutent les méthodes de la
classe Object à vos types primitifs ainsi que des méthodes permettant de caster leurs
valeurs, etc. À ceci, je dois ajouter que depuis Java 5, est géré ce qu'on appelle l'
autoboxing , une fonctionnalité du langage permettant de transformer
automatiquement un type primitif en classe wrapper (on appelle ça le boxing ) et
inversement, c'est-à-dire une classe wrapper en type primitif (ceci s'appelle l' unboxing ).
Ces deux fonctionnalités forment l' autoboxing . Par exemple :
java
Vous devez savoir que la généricité peut être multiple ! Nous avons créé une classe Solo ,
mais rien ne vous empêche de créer une classe Duo , qui elle prend deux paramètres
génériques ! Voilà le code source de cette classe :
java
Vous voyez que cette classe prend deux types de références qui ne sont pas encore
dé nis.
A n de mieux comprendre son fonctionnement, voici un code que vous pouvez tester :
java
Vous voyez qu'il n'y a rien de bien méchant ici. Ce principe fonctionne exactement
comme dans l'exemple précédent. La seule différence réside dans le fait qu'il n'y a pas un,
mais deux paramètres génériques !
… vous violez la contrainte que vous avez émise lors de la déclaration du type de référence
! Vous ne pourrez donc pas modi er la déclaration générique d'un objet. Donc si vous
suivez bien, on va pouvoir encore corser la chose !
Généricité et collections
Vous pouvez aussi utiliser la généricité sur les objets servant à gérer des collections. C'est
même l'un des points les plus utiles de la généricité !
En effet, lorsque vous listiez le contenu d'un ArrayList par exemple, vous n'étiez jamais
sûrs à 100 % du type de référence sur lequel vous alliez tomber (normal, puisqu'un
ArrayList accepte tous les types d'objets)… Eh bien ce calvaire est terminé et le
polymorphisme va pouvoir réapparaître, plus puissant que jamais !
ArrayList et généricité
La généricité sur les listes est régie par les lois vues précédemment : pas de type
float dans un ArrayList<String> .
Héritage et généricité
Là où les choses sont pernicieuses, c'est quand vous employez des classes usant de la
généricité avec des objets comprenant la notion d'héritage ! L'héritage dans la généricité
est l'un des concepts les plus complexes en Java. Pourquoi ? Tout simplement parce qu'il
va à l'encontre de ce que vous avez appris jusqu'à présent…
Nous avons une classe Voiture dont hérite une autre classe VoitureSansPermis , ce qui
nous donnerait le diagramme représenté à la gure suivante.
Hiérarchie de classes
Si vous avez l'habitude de la covariance des variables, sachez que cela n'existe pas avec la
généricité ! En tout cas, pas sous la même forme.
Imaginez deux secondes que l'instruction interdite soit permise ! Dans listVoiture ,
vous avez le contenu de la liste des voitures sans permis, et rien ne vous empêche d'y
ajouter une voiture. Là où le problème prend toute son envergure, c'est lorsque vous
voudrez sortir toutes les voitures sans permis de votre variable listVoiture . Eh oui ! Vous
y avez ajouté une voiture ! Lors du balayage de la liste, vous aurez, à un moment, une
référence de type VoitureSansPermis à laquelle vous tentez d'affecter une référence de
type Voiture . Voilà pourquoi ceci est interdit.
Une des solutions consiste à utiliser le wildcard : « ? ». Le fait de déclarer une collection
avec le wildcard , comme ceci :
java
1 ArrayList<?> list;
… revient à indiquer que notre collection accepte n'importe quel type d'objet. Cependant,
nous allons voir un peu plus loin qu'il y a une restriction.
Je vais maintenant vous indiquer quelque chose d'important. Avec la généricité, vous
pouvez aller encore plus loin. Nous avons vu comment restreindre le contenu d'une de
nos listes, mais nous pouvons aussi l’élargir ! Si je veux par exemple qu'un ArrayList
puisse avoir toutes les instances de Voiture et de ses classes lles… comment faire ?
Ce qui suit s'applique aussi aux interfaces susceptibles d'être implémentées par
une classe !
Une application de ceci consiste à écrire des méthodes génériques, par exemple une
méthode qui permet de lister toutes les valeurs de notre ArrayList cité précédemment :
java
Eh, attends ! On a voulu ajouter des objets dans notre collection et le programme
ne compile plus !
Oui… Ce que je ne vous avais pas dit, c'est que dès que vous utilisez le wildcard , vos listes
sont verrouillées en insertion : elles se transforment en collections en lecture seule..
En fait, il faut savoir que c'est à la compilation du programme que Java ne vous laisse pas
faire : le wildcard signi e « tout objet », et dès l'utilisation de celui-ci, la JVM verrouillera
la compilation du programme a n de prévenir les risques d'erreurs. Dans notre exemple,
il est combiné avec extends (signi ant héritant), mais cela n'a pas d'incidence directe :
c'est le wildcard la cause du verrou (un objet générique comme notre objet Solo
déclaré Solo<?> solo; sera également bloqué en écriture).
Les méthodes déclarées avec un type générique sont verrouillées a n de n'être utilisées
qu'avec ce type bien précis, toujours pour les mêmes raisons ! Attendez : ce n'est pas
encore tout. Nous avons vu comment élargir le contenu de nos collections (pour la
lecture), nous allons voir comment restreindre les collections acceptées par nos
méthodes.
La méthode :
java
… autorise n'importe quel objet de type List dont Voiture est la superclasse.
La signi cation de l'instruction suivante est donc que la méthode autorise un objet de
type List de n'importe quelle superclasse de la classe Voiture (y compris Voiture
elle-même).
java
1 import java.util.ArrayList;
2 import java.util.List;
3
4 public class Garage {
5 List<Voiture> list = new ArrayList<Voiture>();
6
7 public void add(List<? extends Voiture> listVoiture){
8 for(Voiture v : listVoiture)
9 list.add(v);
10
11 System.out.println("Contenu de notre garage :");
12 for(Voiture v : list)
13 System.out.print(v.toString());
14 }
15 }
La généricité est un concept très utile pour développer des objets travaillant avec
plusieurs types de données.
Vous passerez donc moins de temps à développer des classes traitant de façon
identique des données différentes.
La généricité permet de réutiliser sans risque le polymorphisme avec les collections.
Cela confère plus de robustesse à votre code.
Vous pouvez coupler les collections avec la généricité !
Le wildcard (?) permet d'indiquer que n'importe quel type peut être traité et donc
accepté !
Dès que le wildcard (?) est utilisé, cela revient à rendre ladite collection en lecture
seule !
Vous pouvez élargir le champ d'acceptation d'une collection générique grâce au
mot-clé extends .
L'instruction ? super MaClasse autorise toutes les collections de classes ayant pour
type MaClasse et tous ses supertypes !
Pour ce genre de cas, les méthodes génériques sont particulièrement adaptées et
permettent d'utiliser le polymorphisme dans toute sa splendeur !
Nous contacter