开发者

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

In a piece of code I've written,开发者_如何学C 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?


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

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


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.


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.


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>.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜