Muestre un buen ejemplo de covarianza y contravarianza en Java.
fuente
Muestre un buen ejemplo de covarianza y contravarianza en Java.
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 covariantList
que 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 )
Covarianza: Iterable e Iterador. Casi siempre tiene sentido definir una covariante
Iterable
oIterator
.Iterator<? extends T>
se puede usar comoIterator<T>
: el único lugar donde aparece el parámetro de tipo es el tipo de retorno delnext
método, por lo que se puede actualizar de forma seguraT
. Pero si tieneS
extensionesT
, también puede asignarlasIterator<S>
a una variable de tipoIterator<? extends T>
. Por ejemplo, si está definiendo un método de búsqueda:no podrá llamarlo con
List<Integer>
y5
, por lo que está mejor definido comoContravarianza: Comparador.Casi siempre tiene sentido usarlo
Comparator<? super T>
, porque se puede usar comoComparator<T>
. El parámetro de tipo aparece solo como elcompare
tipo de parámetro de método, por lo queT
se le puede pasar de forma segura. Por ejemplo, si tiene unDateComparator implements Comparator<java.util.Date> { ... }
y desea ordenar unList<java.sql.Date>
con ese comparador (java.sql.Date
es una subclase dejava.util.Date
), puede hacerlo con:pero no con
fuente
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.
fuente
contra variant
decir.super.doSomething("String")
no pudo ser reemplazado porsub.doSomething(Object)
.