variable una type tipos recorrer programacion parameter method listas genéricas generic ejemplos collection colecciones java generics

una - t generic java



¿Por qué no puedo lanzar una Colección<GenericFoo> a una Colección<GenericFoo<?>> (1)

En primer lugar, el tipo raw y el tipo de comodín son bastante diferentes. Por un lado, el tipo raw borra completamente toda la información genérica.

Entonces tenemos List<x> y List<y> donde x no es y. Esto ciertamente no es una relación de subtipo.

Sin embargo, puedes pedir que se permita el casting. Pero lea JLS 5.5.1 y dígame que desea agregarle algo más :) Navegue por toda la página, en realidad, es un gran muro de texto solo para el casting .

Y recuerda que esta es solo la primera onda en todo el efecto. ¿Qué pasa con la List<List<x>> y la List<List<y>> , etc.

El quid de la pregunta es, ¿por qué causa esto un error en tiempo de compilación?

List<Collection> raws = new ArrayList<Collection>(); List<Collection<?>> c = raws; // error

Fondo

Entiendo por qué los genéricos no son covariantes en general. Si pudiéramos asignar List<Integer> a List<Number> , nos expondríamos a ClassCastExceptions:

List<Integer> ints = new ArrayList<Integer>(); List<Number> nums = ints; // compile-time error nums.add(Double.valueOf(1.2)); Integer i = ints.get(0); // ClassCastException

Recibimos un error en tiempo de compilación en la línea 2 para evitarnos un error en tiempo de ejecución en la línea 4. Eso tiene sentido.

List<C> para List<C<?>>

Pero ¿qué tal esto?

List<Collection> rawLists = new ArrayList<Collection>(); List<Collection<?>> wildLists = rawLists; // compile-time error // scenario 1: add to raw and get from wild rawLists.add(new ArrayList<Integer>()); Collection<?> c1 = wildLists.get(0); Object o1 = c1.iterator().next(); // scenario 2: add to wild and get from raw wildLists.add(new ArrayList<String>()); Collection c2 = rawLists.get(0); Object o2 = c2.iterator().next();

En ambos escenarios, en última instancia, solo obtengo elementos de Object sin lanzar, por lo que no puedo obtener una ClassCastException "misteriosa".

La sección en el JLS que corresponde a esto es §4.10.2 , así que entiendo por qué el compilador me está dando el error; lo que no entiendo es por qué la especificación se escribió de esta manera, y (para evitar las respuestas especulativas / basadas en la opinión), si realmente me proporciona alguna seguridad en tiempo de compilación.

Ejemplo motivador

En caso de que se lo pregunte, aquí está (una versión simplificada de) el caso de uso:

public Collection<T> readJsons(List<String> jsons, Class<T> clazz) { List<T> list = new ArrayList<T>(); for (String json : jsons) { T elem = jsonMapper.readAs(json, clazz); list.add(elem); } return list; } // call site List<GenericFoo<?>> foos = readJsons(GenericFoo.class); // error

El error se debe a que GenericFoo.class tiene el tipo Class<GenericFoo> , no la Class<GenericFoo<?>> ( §15.8.2 ). No estoy seguro de por qué es eso, aunque sospecho que es una razón relacionada; pero a pesar de eso, eso no sería un problema si la Class<GenericFoo> pudiera Class<GenericFoo> , ya sea implícita o explícitamente, a la Class<GenericFoo<?>> .