web-dev-qa-db-fra.com

Démontrer la covariance et la contravariance en Java?

Veuillez montrer un bon exemple de covariance et de contravariance en Java.

98
JavaUser

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 car 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 surchargerait pas la méthode doSomething (). D'autres langages prennent en charge ce style de contravariance.

Génériques

Ceci est également possible pour les 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 prennent pas de paramètre générique (car il doit être quelque chose "étend l'objet") , mais les getters fonctionneront très bien (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 une), mais pas de getters (le type renvoyé peut être de tout autre supertype de chaîne)

144
Hardcoded

Co-variance: Iterable et Iterator. Il est presque toujours logique de définir une co-variante Iterable ou Iterator. Iterator<? extends T> peut être utilisé comme Iterator<T> - le seul endroit où le paramètre type apparaît est le type de retour de la méthode next, il peut donc être remonté en toute sécurité vers T. Mais si vous avez S étend T, vous pouvez également affecter Iterator<S> vers 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> et 5, il est donc préférable de définir

boolean find(Iterable<?> where, Object what)

Contre-variance: Comparateur. Il est presque toujours logique d'utiliser Comparator<? super T>, car il peut être utilisé comme Comparator<T>. Le paramètre type apparaît uniquement en tant que type de paramètre de méthode compare, afin que T puisse lui être transmis en toute sécurité. Par exemple, si vous avez un DateComparator implements Comparator<Java.util.Date> { ... } et vous voulez 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)
45
Yardena