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>
.
精彩评论