Car le double niveau d'abstraction peut poser problème dans certains cas.
Prenons cet exemple :
Map<String, ? extends Object> map = new HashMap<String, String>();
Ces deux types sont parfaitement compatible (dans ce sens) et permettent de faire abstraction sur le type concret de la valeur de la Map.
Mais ce code est également typesafe : puisqu'on ne connait pas le type exact du second paramètrage on ne peut pas modifier la map : tout appel à put() ou autre méthode de ce type génèrera une erreur de compilation puisque le typage est inconnu...
Maintenant lorsque tu utilises ceci :
Map<String, List<? extends Object>> map
Le typage de la List est inconnu, mais celui de la map est connu et tu peux donc faire ceci :
map.put("test", new List<Integer>());
Or si le compilateur t'autorisait à faire quelque chose du genre de ceci :
Map<String, List<? extends Object>> map = new HashMap<String, List<String>>(); // ERREUR
cela reviendrait à mettre une List<Integer> dans une map de List<String>, ce qui engendrerait des erreurs bien casse-tête lors de l'exécution...
Selon ce que tu veux faire, il faudrait mieux manipuler des types précis en "généricifiant" tes classes/interfaces :
1 2 3 4 5 6 7 8 9
| interface IA<TB extends IB, TC extends IC> {
public Map<TB, List<TC>> getMachin();
}
class AImpl implements IA<BImpl, CImpl> {
public Map<BImpl, List<CImpl>> getMachin(){
return null;
}
} |
a++
Partager