Подтвердить что ты не робот

Невозможно выполнить преобразование из ArrayList <Parcelable> в ArrayList <ClSprite>

В куске кода, который я написал, у меня есть эта строка:

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

Я получаю сообщение об ошибке с недопустимым приводом от ArrayList<Parcelable> до ArrayList<ClSprite>. Почему это не является законным?

4b9b3361

Ответ 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>.