Hoy, leí algunos artículos sobre Covarianza, Contravarianza (e Invarianza) en Java. Leí el artículo de Wikipedia en inglés y alemán, y algunas otras publicaciones de blog y artículos de IBM.
¿Pero todavía estoy un poco confundido sobre de qué se tratan exactamente? Algunos dicen que se trata de la relación entre tipos y subtipos, algunos dicen que se trata de conversión de tipos y algunos dicen que se usa para decidir si un método se anula o se sobrecarga.
Así que estoy buscando una explicación fácil en un lenguaje sencillo, que muestre a un principiante qué es la covarianza y la contravarianza (e invariancia). Punto más para un ejemplo sencillo.
Respuestas:
Todas las anteriores.
En el fondo, estos términos describen cómo la relación de subtipo se ve afectada por las transformaciones de tipo. Es decir, si
A
yB
son tipos,f
es una transformación de tipo, y ≤ la relación de subtipo (es decir,A ≤ B
significa queA
es un subtipo deB
), tenemosf
es covariante siA ≤ B
implica quef(A) ≤ f(B)
f
es contravariante siA ≤ B
implica quef(B) ≤ f(A)
f
es invariante si ninguno de los anteriores se cumpleConsideremos un ejemplo. Deja
f(A) = List<A>
dondeList
es declarado por¿Es
f
covariante, contravariante o invariante? Covariante significaría que aList<String>
es un subtipo deList<Object>
, contravariante que aList<Object>
es un subtipoList<String>
e invariante que ninguno es un subtipo del otro, es decir,List<String>
yList<Object>
son tipos inconvertibles. En Java, esto último es cierto, decimos (un tanto informalmente) que los genéricos son invariantes.Otro ejemplo. Deja
f(A) = A[]
. ¿Esf
covariante, contravariante o invariante? Es decir, ¿String [] es un subtipo de Object [], Object [] es un subtipo de String [], o ninguno es un subtipo del otro? (Respuesta: en Java, las matrices son covariantes)Esto todavía era bastante abstracto. Para hacerlo más concreto, veamos qué operaciones en Java se definen en términos de la relación de subtipo. El ejemplo más simple es la asignación. La declaración
se compilará solo si
typeof(y) ≤ typeof(x)
. Es decir, acabamos de enterarnos de que las declaracionesno se compilará en Java, pero
será.
Otro ejemplo donde la relación de subtipo es importante es una expresión de invocación de método:
Hablando informalmente, esta declaración se evalúa asignando el valor de
a
al primer parámetro del método, luego ejecutando el cuerpo del método y luego asignando el valor de retorno de los métodos aresult
. Al igual que la asignación simple en el último ejemplo, el "lado derecho" debe ser un subtipo del "lado izquierdo", es decir, esta declaración solo puede ser válida sitypeof(a) ≤ typeof(parameter(method))
yreturntype(method) ≤ typeof(result)
. Es decir, si el método es declarado por:ninguna de las siguientes expresiones se compilará:
pero
será.
Otro ejemplo en el que la subtipificación importa es primordial. Considerar:
dónde
De manera informal, el tiempo de ejecución reescribirá esto en:
Para que la línea marcada se compile, el parámetro de método del método reemplazado debe ser un supertipo del parámetro de método del método reemplazado, y el tipo de retorno un subtipo del método reemplazado. Hablando formalmente,
f(A) = parametertype(method asdeclaredin(A))
al menos debe ser contravariante, y sif(A) = returntype(method asdeclaredin(A))
debe ser al menos covariante.Tenga en cuenta el "al menos" de arriba. Esos son requisitos mínimos que cualquier lenguaje de programación orientado a objetos seguro de tipo estático razonable hará cumplir, pero un lenguaje de programación puede optar por ser más estricto. En el caso de Java 1.4, los tipos de parámetros y los tipos de retorno de métodos deben ser idénticos (excepto para el borrado de tipos) cuando se anulan los métodos, es decir,
parametertype(method asdeclaredin(A)) = parametertype(method asdeclaredin(B))
cuando se anulan. Desde Java 1.5, los tipos de retorno covariantes están permitidos al anular, es decir, lo siguiente se compilará en Java 1.5, pero no en Java 1.4:Espero haber cubierto todo, o mejor dicho, haber rayado la superficie. Aún así, espero que ayude a comprender el concepto abstracto, pero importante, de variación de tipos.
fuente
A ≤ B
. Esa notación hace que las cosas sean mucho más simples y significativas. Buena lectura ...Tomando el sistema de tipos java, y luego clases:
Cualquier objeto de algún tipo T puede ser sustituido por un objeto del subtipo T.
VARIENCIA DE TIPO - LOS MÉTODOS DE CLASE TIENEN LAS SIGUIENTES CONSECUENCIAS
Se puede ver que:
Ahora co- y contra- se relacionan con que B sea subtipo de A. Los siguientes tipos más fuertes pueden introducirse con un conocimiento más específico. En el subtipo.
La covarianza (disponible en Java) es útil, para decir que uno devuelve un resultado más específico en el subtipo; especialmente visto cuando A = T y B = S. La contravarianza dice que está preparado para manejar un argumento más general.
fuente
La varianza se trata de relaciones entre clases con diferentes parámetros genéricos. Sus relaciones son la razón por la que podemos elegirlos.
La varianza Co y Contra son cosas bastante lógicas. El sistema de tipos de lenguaje nos obliga a apoyar la lógica de la vida real. Es fácil de entender con el ejemplo.
Covarianza
Por ejemplo, quieres comprar una flor y tienes dos florería en tu ciudad: la tienda de rosas y la tienda de margaritas.
Si le preguntas a alguien "¿dónde está la florería?" y alguien te dice dónde está la tienda de rosas, ¿estaría bien? sí, porque la rosa es una flor, si quieres comprar una flor puedes comprar una rosa. Lo mismo se aplica si alguien te responde con la dirección de la tienda de margaritas. Este es un ejemplo de covarianza : se le permite convertir
A<C>
aA<B>
, dondeC
es una subclase deB
, siA
produce valores genéricos (devuelve como resultado de la función). La covarianza se trata de productores.Tipos:
La pregunta es "¿dónde está la floristería?", La respuesta es "tienda de rosas allí":
Contravarianza
Por ejemplo, quieres regalar flores a tu novia. Si tu novia ama cualquier flor, ¿puedes considerarla como una persona que ama las rosas o como una persona que ama las margaritas? sí, porque si ama cualquier flor, amaría tanto la rosa como la margarita. Este es un ejemplo de la contravarianza : se le permite lanzar
A<B>
aA<C>
, dondeC
es la subclase deB
, siA
consume valor genérico. La contravarianza se trata de consumidores.Tipos:
Estás considerando a tu novia que ama cualquier flor como alguien que ama las rosas, y le estás regalando una rosa:
Puede encontrar más en la Fuente .
fuente