¿Demostrar covarianza y contravarianza en Java?
covariance contravariance (3)
Mire el principio de sustitución de Liskov . En efecto, si la clase B extiende la clase A, entonces usted debería poder usar una B siempre que se requiera una A.
Por favor, muestre un buen ejemplo de covarianza y contravarianza en Java.
Co-varianza: Iterable e Iterador. Casi siempre tiene sentido definir una Iterable
o Iterator
. Iterator<? extends T>
Iterator<? extends T>
se puede usar igual que Iterator<T>
- el único lugar donde aparece el parámetro type es el tipo de devolución del next
método, por lo que se puede subir de forma segura a T
Pero si tiene S
extiende T
, también puede asignar Iterator<S>
a una variable de tipo Iterator<? extends T>
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 se define mejor como
boolean find(Iterable<?> where, Object what)
Contra-varianza: Comparador. Casi siempre tiene sentido usar Comparator<? super T>
Comparator<? super T>
, porque puede usarse como Comparator<T>
. El parámetro tipo aparece solo como el tipo de parámetro del método de compare
, por lo que T
puede pasarse con seguridad. Por ejemplo, si tiene un DateComparator implements Comparator<java.util.Date> { ... }
y desea ordenar una List<java.sql.Date>
con ese comparador ( java.sql.Date
es una subclase de java.util.Date
), puedes hacer con:
<T> void sort(List<T> what, Comparator<? super T> how)
pero no con
<T> void sort(List<T> what, Comparator<T> how)
Covarianza
class Super {
Object getSomething(){}
}
class Sub extends Super {
String getSomething() {}
}
Sub # getSomething es covariante porque devuelve una subclase del tipo de devolución de Super # getSomething (pero cumple el contrato de Super.getSomething ())
Contravariancia
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, de nuevo, cumple el contrato de Super # doSomething)
Aviso: este ejemplo no funciona en Java. El compilador de Java sobrecargaría y no anularía el método doSomething (). Otros idiomas admiten este estilo de contravarianza.
Genéricos
Esto también es posible para Genéricos:
List<String> aList...
List<? extends Object> covariantList = aList;
List<? super String> contravariantList = aList;
Ahora puede acceder a todos los métodos de covariantList
que no toman un parámetro genérico (ya que debe ser algo "extends Object"), pero los getters funcionarán bien (ya que el objeto devuelto siempre será del tipo "Object")
Lo contrario es cierto para contravariantList
: puede acceder a todos los métodos con parámetros genéricos (usted 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 Cuerda)