converted - java type erasure
¿Dónde dice la especificación de Java que la Lista<T> asigna a la Lista<? super T>? (2)
¿Qué significa asignar la lista a <? super B> en realidad significa?
Considere el siguiente programa:
public class Generics {
static class Quux { }
static class Foo extends Quux { }
static class Bar extends Foo { }
public static void main(String... args) {
List<Foo> fooList = new ArrayList<>();
// This is legal Java
List<? super Bar> superBarList = fooList;
// So is this
List<? super Foo> superFooList = fooList;
// However, this is *not* legal Java
superBarList.add(new Quux());
// Neither is this
superFooList.add(new Quux());
// Or this:
superFooList.add(new Object());
// But this is fine
superFooList.add(new Foo());
}
}
¿Por qué sería esto? En primer lugar, hablemos de lo que dice el JLS
Se dice que un argumento de tipo T1 contiene otro argumento de tipo T2, escrito T2 <= T1, si el conjunto de tipos denotado por T2 es probablemente un subconjunto del conjunto de tipos denotado por T1 bajo el cierre reflexivo y transitivo de las siguientes reglas ( donde <: denota subtipo (§4.10)):
- ? super t <=? super S si S <: T
- T <=? super T
Por lo tanto, T <=? super S si S <: T.
... ¿Pero qué significa eso?
¿Si no puedo agregar un new Quux()
o un new Object()
? List<? super Foo>
List<? super Foo>
significa que esta lista solo contiene elementos que son supertipos estrictos para Foo
, pero no sé qué tipo es ese . En otras palabras, ¿puedo declarar que la lista es de un tipo así , pero no puedo agregarle elementos que no estoy 100% seguro de que sean de tipo ? super Foo
? super Foo
Quux
podría ser ese tipo, pero también podría no ser ese tipo.
Por esta razón, asignando una List<Foo>
a ser List<? super Bar>
List<? super Bar>
no permite la contaminación del montón, y en última instancia no es un problema.
Lectura adicional: sección relevante de la explicación genérica de AngelikaLanger
Supongamos que la clase B
hereda de la clase A
El siguiente es Java legal:
List<A> x;
List<? super B> y = x;
En términos de la especificación, esto significa que la List<A>
assignsTo List<? super B>
List<? super B>
. Sin embargo, estoy teniendo problemas para encontrar la parte de la especificación que dice que esto es legal. En particular, creo que deberíamos tener la relación de subtipo
List<A> <: List<? super B>
pero la sección 4.10 de la especificación de Java 8 define la relación de subtipo como el cierre transitivo de una relación de supertipo directa S >1 T
, y define la relación de supertipo directo en términos de una función finita que calcula un conjunto de supertipos de T
No hay una función limitada que en la List<A>
entrada List<A>
puede producir la List<? super B>
List<? super B>
ya que puede haber un número arbitrario de B
s que heredan de A
, por lo que la definición del subtipo de la especificación parece descomponerse para los super comodines. La Sección 4.10.2 sobre "Subtitulado entre clases y tipos de interfaz" sí menciona comodines, pero solo maneja la otra dirección donde el comodín aparece en el subtipo potencial (esta dirección encaja en el mecanismo de supertipo directo calculado).
Pregunta : ¿Qué parte de la especificación dice que el código anterior es legal?
La motivación es para el código del compilador, por lo que no es suficiente entender por qué es legal de manera intuitiva o crear un algoritmo que lo maneje. Dado que el problema general de subtipo en Java es indecidible, me gustaría manejar exactamente los mismos casos que la especificación, y por lo tanto quiero la parte de la especificación que maneja este caso.
List<? super B>
List<? super B>
se define como un supertipo de List<A>
según §4.10.2. Subtipo entre clases y tipos de interfaz :
Los supertipos directos del tipo parametrizado
C<T 1 ,...,T n >
, dondeT i
(1 ≤ i ≤ n) es un tipo, son todos los siguientes:
D<U 1 θ,...,U k θ>
, dondeD<U 1 ,...,U k >
es un supertipo directo deC<T 1 ,...,T n >
yθ
es la sustitución[F 1 :=T 1 ,...,F n :=T n ]
.
C<S 1 ,...,S n >
, dondeS i
contieneT i
(1 ≤ i ≤ n) ( §4.5.1 ).
Sea C<T 1 ,...,T n > = List<A>
y C<S 1 ,...,S n > = List<? super B>
C<S 1 ,...,S n > = List<? super B>
. Según la segunda bala, List<? super B>
List<? super B>
es un supertipo de List<A>
si ? super B
? super B
contiene A
La relación contiene se define en §4.5.1 §4.5.1 :
Se dice que un argumento de tipo
T 1
contiene otro argumento de tipoT 2
, escritoT 2 <= T 1
, si el conjunto de tipos denotado porT 2
es probablemente un subconjunto del conjunto de tipos denotado porT 1
bajo el reflejo y transitivo cierre de las siguientes reglas (donde<:
denota subtipo ( §4.10 )):
? extends T <= ? extends S
? extends T <= ? extends S
siT <: S
? super T <= ? super S
? super T <= ? super S
siS <: T
T <= T
T <= ? extends T
T <= ? super T
Por la segunda bala, podemos ver eso ? super B
? super B
contiene ? super A
? super A
. Por la última bala, vemos eso ? super A
? super A
contiene A
Transitivamente, por lo tanto lo sabemos ? super B
? super B
contiene A