Невозможно выполнить преобразование из ArrayList <Parcelable> в ArrayList <ClSprite>
В куске кода, который я написал, у меня есть эта строка:
AllSprites = (ArrayList<ClSprite>) savedInstanceState.getParcelableArrayList("AllSprites");
Я получаю сообщение об ошибке с недопустимым приводом от ArrayList<Parcelable>
до ArrayList<ClSprite>
. Почему это не является законным?
Ответы
Ответ 1
В принципе небезопасно использовать ArrayList<Derived>
для ArrayList<Base>
или наоборот. Это открывает дыру в системе типов, и Java будет запускать ClassCastException
во время выполнения, если вы попробуете это.
Причина в том, что я мог бы сделать что-то вроде этого:
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 not really a Derived!
Это, кстати, причина того, что Java неявные преобразования между массивами нарушены и почему там ArrayStoreException
. Этот бросок небезопасен во всех случаях.
Ответ 2
Простым решением является установка типа возвращаемого элемента так:
ArrayList<ClSprite> AllSprites = savedInstanceState.<ClSprite>getParcelableArrayList("AllSprites")
Ответ 3
Другие уже объяснили проблему, но в этом случае для нее существует очень простое решение. Просто оставьте бросок, и ваш код будет скомпилирован.:):
ArrayList<ClSprite> AllSprites = savedInstanceState.getParcelableArrayList("AllSprites");
Почему?
Взгляните на подпись метода getParcelableArrayList
:
public <T extends Parcelable> ArrayList<T> getParcelableArrayList(String key)
Это общий метод, параметр типа которого должен быть дочерним элементом Parcelable
. Если вы назначаете его непосредственно такой переменной:
ArrayList<ClSprite> AllSprites; // declaration somewhere
// ClSprite implements Parcelable
...
AllSprites = savedInstanceState.getParcelableArrayList("AllSprites");
компилятор может вывести параметр типа, так что нет необходимости в отливке! После выведения подпись будет выглядеть так:
public ArrayList<ClSprite> getParcelableArrayList(String key)
Понятно, что нам не нужно бросать из ArrayList<ClSprite>
в ArrayList<ClSprite>
.:)
Но почему у вас была эта ошибка? Если вы выполняете приведение и не присваиваете переменную непосредственно возвращаемому значению этого метода, компилятор не может вывести параметр типа, он знает только, что возвращаемый тип ArrayList<Parcelable>
. И в этом случае ошибка приводит к тому, что уже объяснили остальные.
Также, если метод не будет общим, но вот так:
public ArrayList<Parcelable> getParcelableArrayList(String key)
вы не можете присвоить возвращаемое значение AllSprites
, потому что вообще нет никакого вывода типа, и вы не можете преобразовать из ArrayList<Parcelable>
в ArrayList<ClSprite>
.
Несмотря на то, что это имеет смысл, Java использует тип erasure для дженериков и делает эти вещи небезопасными во время выполнения.
Ответ 4
Это просто запрещено в Java; список-родительский не может быть перенесен в список-ребенка. Кроме того, приведение к ArrayList<X>
является опасным и чрезмерно ограничительным. Вы можете исправить обе проблемы, сделав тип AllSprites
be List<Parcelable>
.