interfaz grafica ejemplos componentes java generics casting raw-types unbounded-wildcard

grafica - jframe en java



No se puede convertir de la Lista<Lista> a la Lista<Lista<?>> (3)

Si solo desea eliminar advertencias, puede usar @SuppressWarnings ("tipos de raw").

Básicamente, el problema es que el compilador trata al tipo en bruto como un objeto primitivo genéricos previos, por lo que ... un "objeto antiguo" no es un "objeto genérico", por lo que ... no puede convertirlos.

Lea esto del documento oficial: http://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html

Pero si asigna un tipo sin procesar a un tipo parametrizado, recibe una advertencia:

Caja rawBox = new Box (); // rawBox es un tipo sin formato de Box Box intBox = rawBox; // advertencia: conversión no comprobada También recibe una advertencia si usa un tipo sin procesar para invocar métodos genéricos definidos en el tipo genérico correspondiente:

Box stringBox = new Box <> (); Caja rawBox = stringBox; rawBox.set (8); // advertencia: invocación sin marcar para establecer (T) La advertencia muestra que los tipos sin procesar omiten las comprobaciones de tipo genérico, lo que retrasa la captura del código inseguro en el tiempo de ejecución. Por lo tanto, debe evitar el uso de tipos sin procesar.

Una lista sin formato se convierte en List<?> Simplemente bien. ¿Por qué una lista de listas sin procesar no puede convertirse a una lista de la List<?> ?

{ // works List raw = null; List<?> wild = raw; } { // Type mismatch: cannot convert from List<List> to List<List<?>> List<List> raw = null; List<List<?>> wild = raw; }

Trasfondo (para mitigar el problema xy ):

Una API que estoy usando devuelve List<JAXBElement> . Sé que siempre es List<JAXBElement<String>> . Planeo hacer un bucle y crear mi propia List<String> , pero estaba tratando de corregir (pero no suprimir) la advertencia del compilador de tipo sin List<JAXBElement> raw = api(); cuando escribo List<JAXBElement> raw = api(); .

Lo intenté:

List<JAXBElement<?>> raw = api(); List<JAXBElement<?>> raw = (List<JAXBElement<?>>) api();

pero estos dan el error de desajuste de tipo.

Curiosamente, esto no da advertencia o error:

for (JAXBElement<?> e : api()) { // ... }


No puede asignarlo ni emitirlo directamente , porque Raw List no es lo mismo que List<?> .

Al usar la verificación de tipo de List se ignora y puede utilizar cualquier método genérico con cualquier tipo. Al usar List<?> El compilador no le permitirá usar métodos con parámetros genéricos .

Por lo tanto, puedes ignorar las advertencias:

@SuppressWarnings("rawtypes")

Y / o lanzarlo explícitamente con una solución alternativa:

List<JAXBElement<String>> raw = (List<JAXBElement<String>>) ((Object)api());


// #1 (does compile) List raw = null; List<?> wild = raw; // #2 (doesn''t compile) List<List> raw = null; List<List<?>> wild = raw;

Primero, vamos a aclarar por qué estas son asignaciones realmente no relacionadas. Es decir, están gobernados por reglas diferentes.

# 1 se llama conversión sin marcar :

Existe una conversión no verificada de la clase o tipo de interfaz sin §4.8 ( §4.8 ) G a cualquier tipo parametrizado de la forma G<T 1 ,...,T n > .

Específicamente, es un caso especial de contexto de asignación solo para este escenario:

Si, después de haber aplicado [otras posibles conversiones], el tipo resultante es un tipo sin formato, entonces se puede aplicar una conversión no verificada.

# 2 requiere una conversión de tipo de referencia; sin embargo, el problema es que no se trata de una conversión de ampliación (que es el tipo de conversión de referencia que se permite implícitamente sin conversión).

¿Porqué es eso? Bueno, esto se rige específicamente por las reglas de subtipado genérico y más específicamente este punto:

Dada una declaración de tipo genérico C<F 1 ,...,F n > ( n > 0), los supertipos directos del tipo parametrizado C<T 1 ,...,T n > , donde T i (1 ≤ i)n ) es un tipo, son todos los siguientes:

  • C<S 1 ,...,S n > , donde S i contiene T i (1 ≤ in ).

Esto nos remite a algo que JLS llama containment , donde para ser una asignación válida, los argumentos del lado izquierdo deben contener los argumentos del lado derecho. La contención rige en gran medida la subtipificación genérica ya que los tipos genéricos "concretos" son invariant .

Puede estar familiarizado con las ideas que:

  • una List<Dog> no es una List<Animal>
  • pero una List<Dog> es una List<? extends Animal> List<? extends Animal> .

Bueno, esto último es cierto porque ? extends Animal ? extends Animal contiene Dog .

Entonces, la pregunta se convierte en "¿contiene un argumento de tipo List<?> Un argumento de tipo sin formato List " ? Y la respuesta es no: aunque List<?> Es un subtipo de List , esta relación no se cumple para los argumentos de tipo.

No existe una regla especial que lo haga cierto: List<List<?>> no es un subtipo de List<List> por esencialmente el mismo motivo. List<Dog> no es un subtipo de List<Animal> .

Entonces, como List<List> no es un subtipo de List<List<?>> , la asignación no es válida. Del mismo modo, no puede realizar un molde de conversión de estrechamiento directo porque List<List> tampoco es un supertipo de List<List<?>> .

Para realizar la tarea, aún puedes aplicar un reparto. Hay tres formas de hacerlo que me parecen razonables.

// 1. raw type @SuppressWarnings("unchecked") List<List<?>> list0 = (List) api(); // 2. slightly safer @SuppressWarnings({"unchecked", "rawtypes"}) List<List<?>> list1 = (List<List<?>>) (List<? extends List>) api(); // 3. avoids a raw type warning @SuppressWarnings("unchecked") List<List<?>> list2 = (List<List<?>>) (List<? super List<?>>) api();

(Puede sustituir JAXBElement por la List interna).

Su caso de uso para este casting debería ser seguro porque List<List<?>> es un tipo más restrictivo que List<List> .

  • La instrucción de tipo sin procesar es una asignación ampliada y luego una asignación sin marcar. Esto funciona porque, como se muestra arriba, cualquier tipo parametrizado se puede convertir a su tipo sin procesar y viceversa.

  • La declaración un poco más segura (nombrada así porque pierde menos información de tipo) es un reparto ensanchado que luego reduce el lanzamiento. Esto funciona mediante conversión a un supertipo común:

    List<? extends List> ╱ ╲ List<List<?>> List<List>

    El comodín delimitado permite que los argumentos de tipo sean considerados para la subtipificación a través de la contención.

    ¿El hecho de que List<? extends List> List<? extends List> se considera un supertipo de List<List<?>> se puede probar con transitivity:

    1. ? extends List ? extends List contiene ? extends List<?> ? extends List<?> , porque List es un supertipo de List<?> .

    2. ? extends List<?> ? extends List<?> contiene List<?> .

    3. Por lo tanto ? extends List ? extends List contiene List<?> .

    (Es decir, List<? extends List> :> List<? extends List<?>> :> List<List<?>> )

  • El tercer ejemplo funciona de una manera similar al segundo ejemplo, mediante conversión a un supertipo común List<? super List<?>> List<? super List<?>> . Como no usa un tipo sin formato, podemos suprimir una advertencia menos.

El resumen no técnico aquí es que la especificación implica que no hay subtipo ni relación de supertipo entre List<List> y List<List<?>> .

Aunque la conversión de List<List> a List<List<?>> debería ser segura , no está permitida. (Es seguro porque ambos son una List que puede almacenar cualquier tipo de List , pero una List<List<?>> impone más restricciones sobre cómo se pueden usar sus elementos después de que se recuperan).

Desafortunadamente, no hay una razón práctica que no compile, excepto que los tipos crudos son extraños y el uso de ellos es problemático.