2011-08-05 11 views
12

En un trozo de código que he escrito, tengo esta línea:no puede lanzar desde ArrayList <Parcelable> a ArrayList <ClSprite>

  AllSprites = (ArrayList<ClSprite>) savedInstanceState.getParcelableArrayList("AllSprites"); 

Recibo un error sobre un reparto no válido desde un ArrayList<Parcelable> a ArrayList<ClSprite>. ¿Por qué no es esto legal?

+0

... Está bien, ¿cuál es tu pregunta ** **? –

+0

posible duplicado de [genéricos en Java] (http://stackoverflow.com/questions/1794842/generics-in-java) – Thilo

+2

mirada en el título, no puede emitir desde ArrayList a ArrayList

Respuesta

7

Es fundamentalmente inseguro lanzar un ArrayList<Derived> a un ArrayList<Base> o viceversa. Si lo hace, se abre un agujero en el sistema de tipos, y Java lanzará un ClassCastException en tiempo de ejecución si intenta esto.

La razón es que yo podría hacer algo como esto:

ArrayList<Derived> derived = new ArrayList<Derived>(); 
ArrayList<Base> base = (ArrayList<Derived>) derived; // Not legal! 
base.add(new Base()); // Just put a Base into the list, but it only holds Derived! 
derived.get(0).doSomethingOnlyInDerived(); // Error! It's not really a Derived! 

Esta es la razón, por cierto, que las conversiones implícitas de Java entre matrices se rompen y por qué hay ArrayStoreException. Este yeso no es seguro en todos los casos.

5

Ese lanzamiento es simplemente ilegal en Java; una lista de padres no se puede convertir a una lista de niños. Además, el lanzamiento a ArrayList<X> es peligroso y excesivamente restrictivo. Puede solucionar ambos problemas haciendo que el tipo de AllSprites sea List<Parcelable>.

+0

¿Cómo puedo hacer esto ya que necesito las funciones en mi clase personalizada, ClSprites. –

+0

Puede simplemente lanzar cada objeto en la 'Lista' como lo usa, o puede crear una nueva 'Lista ' y mover los objetos de la otra lista en un bucle 'for'. Ninguna de las soluciones parece ideal, pero me temo que no hay una manera más limpia. –

17

Otros ya explicaron el problema, pero en este caso, hay una solución muy simple para ello. Simplemente abandone el elenco y su código se compilará. :):

ArrayList<ClSprite> AllSprites = savedInstanceState.getParcelableArrayList("AllSprites"); 

¿Por qué?

Tome un vistazo a la firma del método getParcelableArrayList:

public <T extends Parcelable> ArrayList<T> getParcelableArrayList(String key) 

Es un método genérico cuyo parámetro de tipo debe ser un hijo de Parcelable. Si se asigna directamente a una variable de la siguiente manera:

ArrayList<ClSprite> AllSprites; // declaration somewhere 
           // ClSprite implements Parcelable 
... 

AllSprites = savedInstanceState.getParcelableArrayList("AllSprites"); 

el compilador puede deducir el tipo de parámetro, así que no hay necesidad del reparto en absoluto! Después de deducir, la firma se vería así:

public ArrayList<ClSprite> getParcelableArrayList(String key) 

Está claro que el que no tenemos a emitir a partir ArrayList<ClSprite> a ArrayList<ClSprite>. :)

¿Pero por qué obtuviste este error? Si realiza un molde y no asigna la variable directamente al valor de retorno de este método, el compilador no puede deducir el parámetro tipo, solo sabe que el tipo devuelto es ArrayList<Parcelable>. Y en este caso, el error tiene lugar lo que los otros ya explicaron.

Además, si el método no sería genérico, pero como esto:

public ArrayList<Parcelable> getParcelableArrayList(String key) 

que no pudo asignar el valor devuelto a AllSprites, porque no hay ningún tipo de deducción en absoluto, y no se puede convertir de ArrayList<Parcelable> a ArrayList<ClSprite>. A pesar de que tendría sentido, Java usa type erasure para genéricos, y hace estas cosas inseguras en tiempo de ejecución.

+0

gracias por la gran explicación, traté de establecer el valor de una ArrayList utilizando un operador ternario, que no funciona. Y esta respuesta lo explica perfectamente. –

+0

Gracias este error para siempre, te amo –

25

Una solución sencilla es configurar el tipo de elemento de retorno igual que

ArrayList<ClSprite> AllSprites = savedInstanceState.<ClSprite>getParcelableArrayList("AllSprites")

+5

Esta es la respuesta más simple y brillante a este problema. Esta debería ser la respuesta aceptada, supongo. – tasomaniac

+0

¡La mejor respuesta! – Pauland

+0

Y es compatible con el compilador javac (utilizado por AndroidStudio). El casting genérico que utilicé funciona en eclipse, pero no en Android Studio. Debería ser aceptada la respuesta. – bajicdusko

-1
ArrayList<NewPost> news = new ArrayList<>(); 
news.addAll(List); 
+2

Agregue una explicación a su código para que el póster pueda comprender mejor su solución. –

+0

Puede entenderse de una manera simple: Los más grandes no se pueden contener en los más pequeños La lista es más grande ArrayList es más pequeña Solo se puede list.add (ArrayList); ¡Espero que pueda ayudarlo! –

Cuestiones relacionadas