2011-12-20 29 views
9

Me encontré con algo que no entiendo. ¿Por qué no es legal para cada bucle debajo cuando el segundo es idéntico?Genéricos de Java y tipos de devolución

public interface SomeInterface<T> { 
    List<SomeNamedObject> getObjects(); 
    void doSomething(P1 p1, T p2); 
} 

public class SomeNamedObject { 
    private String text; 
} 

public class Clazz { 

    private SomeInterface someInterface; 

    ... 

    public void someMethod() { 
     // Error Type mismatch: cannot convert from element type Object to TestClass.SomeNamedObject 
     for (SomeNamedObject someNamedObject : someInterface.getObjects()) { 
      // This loop won't compile as the someInterface.getObjects returns just a List and not a List<SomeNamedObject> 
     } 

     // Warning Type safety: The expression of type List needs unchecked 
     // conversion to conform to List<TestClass.SomeNamedObject> 
     List<SomeNamedObject> objects = someInterface.getObjects(); 
     for (SomeNamedObject someNamedObject : objects) { 
      // This loop compiles 
     } 
    } 
} 
+0

No es un error, es un problema con el borrado y los tipos crudos. – Stefan

+0

No veo cuál podría ser el problema. ¿Puedes publicar el rastro de la pila real (solo las primeras líneas). Supongo que su clase completa requiere "SomeInterface ", pero el ejemplo no requiere el "" ¿Quizás hay algo allí? – Jay

+1

@Jay su declaración de someInterface no especifica el tipo genérico, Java vuelve a los tipos crudos y la firma del método cambia para devolver una Lista sin formato (ver respuestas). Debería haber mencionado la advertencia en la asignación de objetos aunque. – Stefan

Respuesta

18

Debido a que su instancia de variable private SomeInterface someInterface no especifica su parámetro de tipo genérico y luego todo el uso de los genéricos es desactivado para someInterface. Esto significa que someInterface.getObjects() tiene el tipo de devolución sin procesar List en lugar de List<SomeNamedObject>. Esta es la razón por la cual el primer ejemplo no se compila.

En el segundo ejemplo, List<SomeNamedObject> objects = someInterface.getObjects() está poniendo un tipo explícito para la lista. Sin embargo, verá una advertencia cuando lo haga porque la seguridad del tipo no está garantizada. Este es el mismo comportamiento que vería si getObjects() se definió como List getObjects() sin el parámetro de tipo.

+0

Puede ser un error ortográfico en el original, pero 'SomeInterface ' no utiliza 'T' para especificar el tipo genérico para la 'Lista' que se devuelve, que está codificado como' SomeNamedObject'. Por lo tanto, aunque la variable de instancia no está escrita, no debería afectar la 'Lista' devuelta. –

+5

Si el parámetro genérico no se especifica en la declaración de 'someInterface', * todos los * tipos genéricos en 'SomeInterface' se ignoran/deshabilitan incluso si no dependen de 'T'. – mikej

+0

Muy interesante, aunque peculiar. –

3

Debe tener en cuenta que obtendrá una advertencia de compilación cuando asigne objetos antes del segundo ciclo.

Type safety: The expression of type List needs unchecked conversion to conform to 
List<TestClass.SomeNamedObject> 

Esto le habría dicho que por alguna razón sus getObjects() método devuelve una lista no generified. Lo que explica por qué el primer ciclo no compila.

porque se le olvidó generify su referencia:

private SomeInterface someInterface; 

Si no generify que todo va a utilizar el tipo de crudo, incluyendo la firma del método declarado. Significa que devuelve un objeto de lista prima en lugar de una lista <SomeNamedObject> hacer algo como

private SomeInterface<Object> someInterface; 

y debería funcionar.