Envoyé par
LGnord
Mais il doit quand même exister des cas où utiliser un type paramètré par '? extends A' est util?
Dans plein de cas : le problème lorsque tu utilises Set<A> c'est que tu n'est plus du tout générique puisque justement fortement typé !
Prenons un autre exemple, mettons que nous avons une classe Person contenant principalement le nom et l'email de la personne (avec les accesseurs qui vont bien), et plusieurs classes filles qui gère des spécificités pour les clients, fournisseurs ou encore les employées via les sous-classes Customer, Supplier et Employee.
L'application ou les applications pourraient être amenés à utiliser plusieurs types de collections :
- Set<Person> lorsqu'on manipule plusieurs types de personnes différents.
- Set<Customer> pour le service client.
- Set<Supplier> pour la gestion des achats auprès des fournisseurs.
- Set<Employee> pour la payes...
Dans une classe utilitaire on voudrait permettre d'envoyer un simple mail à un ensemble de destinataire. On serait tenter d'écrire ceci :
1 2 3 4 5 6 7 8 9 10 11
| public static void sendMail(String text, Set<Person> recipients) {
Email email = ... // une classe qui gère les emails
for (Person p : recipients) {
email.addRecipient(p.getEmail());
}
email.setContent(text);
email.send();
} |
Le problème c'est qu'on est fortement typé et qu'un Set<Customer> n'est pas un Set<Person>... On ne pourra donc pas utiliser notre méthode aussi facilement que possible et il faudra soit dupliqué du code, soit effectué diverses transformations plutôt inutile.
Or dans notre méthode sendMail() on se fiche de connaitre le type exact de la liste, du moment qu'il s'agit bien d'une liste de personnes...
En changeant simplement la déclaration du paramètre générique on corrige directement ce petit problème :
public static void sendMail(String text, Set<? extends Person> recipients) {
On peut désormais utiliser notre méthode avec n'importe quel type de liste de personnes, quelque soit le type précis de la liste
En contrepartie on ne peut pas modifier la liste mais c'est logique puisqu'on ne connait pas exactement le type de la liste !
Le ? super T permet exactement l'inverse, mais l'intérêt est un peu moins évident à comprendre...
Il ne faut pas oublier non plus qu'avec les méthodes Generics ont peut avoir des liens entre les types des différents paramètres. Par exemple la méthode Collections.copy() déclaré de la manière suivante :
public static <T> void copy(List<? super T> dest, List<? extends T> src)
Permet de copier tous les éléments d'une liste de T (ou de type fils) vers une liste d'un type quelquonque mais parent de T (qui peut donc comporter des éléments du type T).
Ce qui fait que les types des deux listes ne doivent pas impérativement être du même type, mais doivent rester cohérente, par exemple ceci est possible :
1 2 3 4
| List<Number> listNumber = ...
List<Double> listDouble = ...
Collections.copy(listNumber, listDouble); |
Mais pas l'inverse !
Si on n'aurait pas utiliser les wildcard, et qu'on se serait contenter de ceci :
public static <T> void copy(List<T> dest, List<T> src)
Le code ci-dessus n'aurait pas été possible et les deux List auraient dû être exactement du même type Générics...
Ce n'est pas forcément évident à comprendre, mais les wildcards ont un gros intérêt dans les Generics, et peut-être même que tu as déjà utilisé des méthodes les utilisant sans t'en apercevoir
a++
Partager