type converted cannot java generics bounded-wildcard subtyping

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

De la JLS, §4.5.1:

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 > , donde T i (1 ≤ i ≤ n) es un tipo, son todos los siguientes:

  • D<U 1 θ,...,U k θ> , donde D<U 1 ,...,U k > es un supertipo directo de C<T 1 ,...,T n > y θ es la sustitución [F 1 :=T 1 ,...,F n :=T n ] .

  • C<S 1 ,...,S n > , donde S i contiene T 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 tipo T 2 , escrito T 2 <= T 1 , si el conjunto de tipos denotado por T 2 es probablemente un subconjunto del conjunto de tipos denotado por T 1 bajo el reflejo y transitivo cierre de las siguientes reglas (donde <: denota subtipo ( §4.10 )):

  • ? extends T <= ? extends S ? extends T <= ? extends S si T <: S

  • ? super T <= ? super S ? super T <= ? super S si S <: 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