Cannot cast from ArrayList<Parcelable> to ArrayList<ClSprite>

爷,独闯天下 提交于 2020-01-02 01:11:10

问题


In a piece of code I've written, I have this line:

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

I'm getting an error about an invalid cast from an ArrayList<Parcelable> to ArrayList<ClSprite>. Why isn't this legal?


回答1:


It is fundamentally unsafe to cast an ArrayList<Derived> to an ArrayList<Base> or vice-versa. Doing so opens up a hole in the type system, and Java will throw a ClassCastException at runtime if you try this.

The reason is that I could do something like this:

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!

This is the reason, by the way, that Java's implicit conversions between arrays are broken and why there's ArrayStoreException. This cast isn't safe under all cases.




回答2:


A simple solution is to set the returning element type like so

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




回答3:


Others already explained the problem, but in this case, there is a very simple solution for it. Simply leave the cast, and your code will compile. :) :

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

Why?

Take a look at the signature of the getParcelableArrayList method:

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

It's a generic method whose type parameter must be a child of Parcelable. If you assign it directly to a variable like this:

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

AllSprites = savedInstanceState.getParcelableArrayList("AllSprites");

the compiler can deduce the type parameter, so there is no need the cast at all! After deducing, the signature would look like this:

public ArrayList<ClSprite> getParcelableArrayList(String key)

It is clear the we do not have to cast from ArrayList<ClSprite> to ArrayList<ClSprite>. :)

But why did you got this error? If you perform a cast and not assign the variable directly to the return value of this method, the compiler cannot deduce the type parameter, it only knows that the returned type is ArrayList<Parcelable>. And in this case, the error takes places what the others already explained.

Also if the method would not be generic, but like this:

public ArrayList<Parcelable> getParcelableArrayList(String key)

you could not assign the return value to AllSprites, because there is no type deduction at all, and you cannot convert from ArrayList<Parcelable> to ArrayList<ClSprite>. Even though it would make sense, Java uses type erasure for generics, and makes these things unsafe at runtime.




回答4:


That cast is simply illegal in Java; a list-of-parent can't be cast to a list-of-child. Furthermore, the cast to ArrayList<X> is dangerous and overly restrictive. You could fix both problems by making the type of AllSprites be List<Parcelable>.



来源:https://stackoverflow.com/questions/6951306/cannot-cast-from-arraylistparcelable-to-arraylistclsprite

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!