¿Dar ejemplos de funciones que demuestren covarianza y contravarianza en los casos de sobrecarga y anulación en Java? [cerrado]

Respuestas:

155

Covarianza:

class Super {
  Object getSomething(){}
}
class Sub extends Super {
  String getSomething() {}
}

Sub # getSomething es covariante porque devuelve una subclase del tipo de retorno de Super # getSomething (pero cumple el contrato de Super.getSomething ())

Contravarianza

class Super{
  void doSomething(String parameter)
}
class Sub extends Super{
  void doSomething(Object parameter)
}

Sub # doSomething es contravariante porque toma un parámetro de una superclase del parámetro de Super # doSomething (pero, nuevamente, cumple el contrato de Super # doSomething)

Aviso: este ejemplo no funciona en Java. El compilador de Java se sobrecargaría y no anularía el método doSomething (). Otros lenguajes admiten este estilo de contravarianza.

Genéricos

Esto también es posible para los genéricos:

List<String> aList...
List<? extends Object> covariantList = aList;
List<? super String> contravariantList = aList;

Ahora puede acceder a todos los métodos covariantListque no toman un parámetro genérico (ya que debe ser algo "extiende Objeto"), pero los captadores funcionarán bien (ya que el objeto devuelto siempre será del tipo "Objeto")

Lo contrario es cierto para contravariantList: Puede acceder a todos los métodos con parámetros genéricos (sabe que debe ser una superclase de "String", por lo que siempre puede pasar uno), pero no getters (el tipo devuelto puede ser de cualquier otro supertipo de String )

Codificado
fuente
79
El primer ejemplo de contravarianza no funciona en Java. doSomething () en la clase Sub es una sobrecarga, no una anulación.
Craig P. Motlin
15
En efecto. Java no admite argumentos contravariantes en el subtipo. Solo covarianza para lo que se refiere a los tipos de retorno del método (como en el primer ejemplo).
the_dark_destructor
Gran respuesta. La covarianza me parece lógica. Pero, ¿podría señalarme un párrafo en JLS que describa la contravarianza? ¿Por qué se invoca Sub.doSomething?
Mikhail
2
Como señaló Craig, no lo es. Creo que aquí hay un choque entre anular y sobrecargar y SUN eligió (como siempre) la opción compatible con versiones anteriores. Entonces, en Java no puede usar parámetros contravariantes al anular un método.
Codificado el
1
Sería bueno saber por qué recibo votos negativos por mi respuesta.
Codificado el
48

Covarianza: Iterable e Iterador. Casi siempre tiene sentido definir una covariante Iterableo Iterator. Iterator<? extends T>se puede usar como Iterator<T>: el único lugar donde aparece el parámetro de tipo es el tipo de retorno del nextmétodo, por lo que se puede actualizar de forma segura T. Pero si tiene Sextensiones T, también puede asignarlas Iterator<S>a una variable de tipo Iterator<? extends T>. Por ejemplo, si está definiendo un método de búsqueda:

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

no podrá llamarlo con List<Integer>y 5, por lo que está mejor definido como

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

Contravarianza: Comparador.Casi siempre tiene sentido usarlo Comparator<? super T>, porque se puede usar como Comparator<T>. El parámetro de tipo aparece solo como el comparetipo de parámetro de método, por lo que Tse le puede pasar de forma segura. Por ejemplo, si tiene un DateComparator implements Comparator<java.util.Date> { ... }y desea ordenar un List<java.sql.Date>con ese comparador ( java.sql.Datees una subclase de java.util.Date), puede hacerlo con:

<T> void sort(List<T> what, Comparator<? super T> how)

pero no con

<T> void sort(List<T> what, Comparator<T> how)
Yardena
fuente
-4

Mire el principio de sustitución de Liskov . En efecto, si la clase B extiende la clase A, entonces debería poder usar una B siempre que se requiera una A.

extraneón
fuente
6
Esto no responde a la pregunta y es engañoso. Sería completamente posible diseñar un sistema de variantes que rompa la corrección semántica y, por lo tanto, viole la LSP.
Matt Whipple
este no es el caso para contra variantdecir. super.doSomething("String")no pudo ser reemplazado por sub.doSomething(Object).
zinking
No es la cuestión
OlivierTerrien