2010-08-04 15 views
7

Creo que el título debe explicar todo, pero por si acaso ...¿Cuáles son los riesgos de invocación explícita desde una lista de tipo List <? extiende MyObject> a una lista de tipo List <MyObject> en Java?

Quiero saber qué riesgos y problemas potenciales relacionados con la fundición pueden surgir a partir del siguiente fragmento de código Java:

List<? extends MyObject> wildcardList = someAPI.getList(); 
List<MyObject> typedList = (List<MyObject>) wildcardList; 

Mi opinión es que todos los objetos de la wildcardList deberían ser una instancia de MyObject (tipo o subclase exacto) y, por lo tanto, siempre que se recuperen objetos de typedList, nunca debería haber una ClassCastException. ¿Es esto correcto? Si es así, ¿por qué el compilador genera una advertencia?

Respuesta

2

Tiene la palabra acerca de la recuperación de objetos de typedList, esto debería funcionar.

El problema es cuando más adelante agrega más objetos a typedList. Si, por ejemplo, MyObject tiene dos subclases A y B, y wildcardList fue de tipo A, entonces no puede agregarle una B. Pero dado que typedList es del tipo padre MyObject, este error solo se detectará en el tiempo de ejecución.

+0

sí. Thomas es absolutamente correcto – Neel

0

Esto es similar a

List<Object> obj = (List<Object>) new ArrayList<String>(); 

espero que el problema es evidente. La lista de subtipos no se puede convertir en Listas de supertipos.

+0

Esto ni siquiera compila. Pero lo que el OP está haciendo se compilará pero podría fallar en el tiempo de ejecución. –

+0

Sí, eso es correcto. Pero solo quería demostrar que había algo fundamentalmente incorrecto. – Rahul

7

No debería haber ningún problema siempre que solo recupere objetos de la lista. Sin embargo, podría dar lugar a excepción de ejecución si se invoca algunos otros métodos en él como el siguiente código demuestran:

List<Integer> intList = new ArrayList<Integer>(); 
    intList.add(2); 

    List<? extends Number> numList = intList; 
    List<Number> strictNumList = (List<Number>) numList; 
    strictNumList.add(3.5f); 

    int num = intList.get(1); //java.lang.ClassCastException: java.lang.Float cannot be cast to java.lang.Integer 
+1

+1, buen ejemplo. Sin embargo, vale la pena señalar que, siempre que solo llame a las operaciones de tipo "obtener" **, ni siquiera necesita/se beneficia del reparto **. El * único * momento que necesitaría para emitir es si desea hacer algo "inseguro" (con una posible excepción para llamar a métodos de biblioteca que no son tan flexibles como deberían ser con sus parámetros genéricos). –

1

Considere haces algo como:

List<ChildClassOne> childClassList = new ArrayList<ChildClassOne>(); 
childClassList.add(childClassOneInstanceOne); 
childClassList.add(childClassOneInstanceTwo); 

List<? extends MyObject> wildcardList = childClasslist; // works fine - imagine that you get this from a method that only returns List<ChildClassOne> 
List<MyObject> typedList = (List<MyObject>) wildcardList; // warning 

typedList.add(childClassTwoInstanceOne); // oops my childClassList now contains a childClassTwo instance 
ChildClassOne a = childClassList.get(2); // ClassCastException - can't cast ChildClassTwo to ChildClassOne 

Este es el único problema importante. Pero si solo lees de tu lista, debería estar bien.

Cuestiones relacionadas