Aquí está mi comprensión.
Supongamos que tenemos un tipo genérico con 2 métodos
type L<T>
T get();
void set(T);
Supongamos que tenemos un super tipo P
, y tiene subtipos C1, C2 ... Cn
. (Por conveniencia decimos P
es un subtipo de la misma, y es en realidad uno de los Ci
)
Ahora también conseguimos n tipos concretos L<C1>, L<C2> ... L<Cn>
, como si hemos escrito manualmente n tipos:
type L_Ci_
Ci get();
void set(Ci);
No tuvimos que escribirlos manualmente, ese es el punto. Hay no hay relaciones entre estos tipos
L<Ci> oi = ...;
L<Cj> oj = oi; // doesn't compile. L<Ci> and L<Cj> are not compatible types.
Para la plantilla de C++, que es el fin de la historia. Básicamente se trata de expansión macro, basada en una clase de "plantilla", genera muchas clases concretas, sin relaciones de tipo entre ellas.
Para Java, hay más. También conseguimos un tipo L<? extends P>
, es un tipo súper de cualquier L<Ci>
L<Ci> oi = ...;
L<? extends P> o = oi; // ok, assign subtype to supertype
¿Qué clase de método debe existir en L<? extends P>
? Como supertype, cualquiera de sus métodos debe estar oculto por sus subtipos. Este método funcionaría:
type L<? extends P>
P get();
porque en cualquiera de sus subtipo L<Ci>
, hay un método Ci get()
, que es compatible con P get()
- el método predominante tiene la misma firma y tipo de retorno covariantes.
Esto no puede trabajar para set()
sin embargo - no podemos encontrar un tipo X
, de manera que void set(X)
puede ser anulado por void set(Ci)
para cualquier Ci
. Por lo tanto, el método set()
no existe en L<? extends P>
.
También hay un L<? super P>
que va en la dirección opuesta. Tiene set(P)
, pero no get()
. Si Si
es un tipo estupendo de P
, L<? super P>
es un tipo estupendo de L<Si>
.
type L<? super P>
void set(P);
type L<Si>
Si get();
void set(Si);
set(Si)
"anulaciones" set(P)
no en el sentido habitual, pero el compilador puede ver que cualquier invocación válida en set(P)
es una invocación válida en set(Si)
Mal ejemplo de polimorfismo, que pienso? Un "niño" no es (siempre) un "padre". – justhalf
@justhalf: 'Parent' estaba en la pregunta, y sugiere que' Child' es un ejemplo natural de una subclase. No los nombres de clase que habría elegido desde cero, pero lo suficientemente claros en términos del contexto del que se trata la pregunta. –
Sí, entiendo, pero creo que hubiera sido mejor si el ejemplo aquí utiliza "SingleParent" o "NewParent" como la subclase =) – justhalf