2010-11-19 17 views
5

yo esperaría que este código para lanzar una ClassCastException:¿Por qué no falla este elenco genérico?

public class Generics { 
    public static void main(String[] args) { 
     method(Integer.class); 
    } 

    public static <T> T method(Class<T> t) { 
     return (T) new String(); 
    } 
} 

pero no es así. Fundición de cuerda a T no falla, hasta que yo utilizo el objeto devuelto de alguna manera, como:

public class Generics { 
    public static void main(String[] args) { 
     method(Integer.class).intValue(); 
    } 

    public static <T> T method(Class<T> t) { 
     return (T) new String(); 
    } 
} 

Antecedentes: He creado una clase que utiliza JAXB para deserializar un archivo XML. Se ve así:

public static <T> T unmarshal(File file, Class<? extends T> clazz) 

Dependiendo de si la raíz-Element es un tipo anónimo o no, se devuelve T o JAXBElement. JAXBElement, por supuesto, no se puede convertir a T. En mi prueba de unidad, donde solo llamé a unmarshal() sin hacer algo con el resultado, todo funcionó bien. En el Código, falló.

¿Por qué no falla directamente? ¿Es esto un error? Si no, me gustaría entender por qué.

+1

Bueno, * no * produce una advertencia. – Jeremy

Respuesta

4

No se ha especificado explícitamente, por lo que T es Object.

Así que la mirada mirar hacia arriba como esto

public class Generics { 

    public static void main(String[] args) { 
     Generics.method(Integer.class).intValue(); 
    } 

    public static Object method(Class<Object> t) { 
     return (Object) new String(); 
    } 
} 

Si especifica el parámetro genérico:

public class Generics { 

    public static void main(String[] args) { 
     Generics.<Integer>method(Integer.class).intValue(); 
    } 

    public static <T> T method(Class<T> t) { 
     return (T) new String(); 
    } 
} 

obtendrá esa excepción.

4

Si T no se especifica explícitamente, el borrado de tipo lo tratará como Object. Por lo tanto, su objeto String se puede convertir ...

1

pienso que usted puede hacer más fuerte la definición del método de esta manera:

public static <T extends Number> T method(Class<T> t) { 
    return //// some code. 
} 

En este caso la línea return new String() simplemente no puede ser compilado.

pero la línea devuelve el nuevo número entero (123); está compilado, funciona y no requiere casting.

Cuestiones relacionadas