Veuillez montrer un bon exemple de covariance et de contravariance en Java.
Le premier exemple de contravariance ne fonctionne pas en Java. doSomething() dans la classe Sub est une surcharge, pas une surcharge.
Veuillez montrer un bon exemple de covariance et de contravariance en Java.
Covariance :
class Super {
Object getSomething(){}
}
class Sub extends Super {
String getSomething() {}
}
Sub#getSomething est covariant car il renvoie une sous-classe du type de retour de Super#getSomething (mais remplit le contrat de Super.getSomething()).
Contravariance
class Super{
void doSomething(String parameter)
}
class Sub extends Super{
void doSomething(Object parameter)
}
Sub#doSomething est contravariant parce qu'il prend un paramètre d'une superclasse du paramètre de Super#doSomething (mais, encore une fois, remplit le contrat de Super#doSomething)
Remarque : cet exemple ne fonctionne pas en Java. Le compilateur Java surchargerait et ne remplacerait pas la méthode doSomething()-. D'autres langages supportent ce style de contravariance.
Génériques
Cela est également possible pour les produits génériques :
List<String> aList...
List<? extends Object> covariantList = aList;
List<? super String> contravariantList = aList;
Vous pouvez maintenant accéder à toutes les méthodes de covariantList
qui ne prend pas de paramètre générique (car il doit soit quelque chose comme "extends Object"), mais les getters fonctionneront sans problème (car l'objet retourné sera toujours de type "Object").
L'inverse est vrai pour contravariantList
: Vous pouvez accéder à toutes les méthodes avec des paramètres génériques (vous savez qu'il doit s'agir d'une superclasse de "String", vous pouvez donc toujours en passer un), mais pas de getters (le type retourné peut être de n'importe quelle autre superclasse de String).
Le premier exemple de contravariance ne fonctionne pas en Java. doSomething() dans la classe Sub est une surcharge, pas une surcharge.
En effet. Java ne prend pas en charge les arguments contravariants dans le sous-typage. Seule la covariance concerne les types de retour des méthodes (comme dans le premier exemple).
Excellente réponse. La covariance me semble logique. Mais pourriez-vous m'indiquer un paragraphe dans JLS qui décrit la contravariance ? Pourquoi Sub.doSomething est invoqué ?
Co-variance : Iterable et Iterator. Il est presque toujours judicieux de définir une co-variante Iterable
o Iterator
. Iterator<? extends T>
peut être utilisé de la même manière que Iterator<T>
- le seul endroit où le paramètre de type apparaît est le type de retour de la fonction next
de sorte que l'on peut sans risque la faire passer à la méthode T
. Mais si vous avez S
s'étend T
, vous pouvez également assigner Iterator<S>
à une variable de type Iterator<? extends T>
. Par exemple, si vous définissez une méthode de recherche :
boolean find(Iterable<Object> where, Object what)
vous ne pourrez pas l'appeler avec List<Integer>
y 5
Il est donc préférable de le définir comme suit
boolean find(Iterable<?> where, Object what)
Contre-variance : Comparateur. Il est presque toujours judicieux d'utiliser Comparator<? super T>
parce qu'il peut être utilisé de la même manière que le Comparator<T>
. Le paramètre de type n'apparaît qu'en tant que compare
le type de paramètre de la méthode T
peut lui être transmis en toute sécurité. Par exemple, si vous avez un DateComparator implements Comparator<java.util.Date> { ... }
et que vous souhaitez trier un List<java.sql.Date>
avec ce comparateur ( java.sql.Date
est une sous-classe de java.util.Date
), vous pouvez faire avec :
<T> void sort(List<T> what, Comparator<? super T> how)
mais pas avec
<T> void sort(List<T> what, Comparator<T> how)
Vous trouverez des informations à ce sujet sur wikipedia :
http://en.wikipedia.org/wiki/Covariance_and_contravariance_(informatique)#Java
Regardez le Principe de substitution de Liskov . En effet, si la classe B étend la classe A, vous devriez pouvoir utiliser une B chaque fois qu'une A est nécessaire.
Cela ne répond pas à la question et est trompeur. Il serait tout à fait possible de concevoir un système de variantes qui rompe la correction sémantique et viole donc la PSL.
Ce n'est pas le cas pour contra variant
dire. super.doSomething("String")
n'a pas pu être remplacée par sub.doSomething(Object)
.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.