java: (String[])List.toArray() дает ClassCastException

Следующий код (запущенный в Android) всегда дает мне ClassCastException в 3-й строке:

final String[] v1 = i18nCategory.translation.get(id);
final ArrayList<String> v2 = new ArrayList<String>(Arrays.asList(v1));
String[] v3 = (String[])v2.toArray();

Это происходит также, когда v2 является Object[0], а также когда в нем есть строки. Любая идея, почему?


person Gavriel    schedule 16.04.2011    source источник
comment
Вы можете прочитать о ковариантности и контравариантности -- en.wikipedia.org/wiki /   -  person Hut8    schedule 17.04.2011
comment
Как насчет случая, когда T — это интерфейс с фабричным методом для инстанцирования.   -  person sebaj    schedule 07.09.2011
comment
@LaceCard - это очень косвенно связано с ковариантностью/контравариантностью. Настоящая проблема заключается в том, что это прямое следствие указанного поведения метода toArray().   -  person Stephen C    schedule 03.08.2013


Ответы (4)


Это потому, что когда вы используете

 toArray() 

он возвращает Object[], который не может быть приведен к String[] (даже если содержимое является строкой). Это связано с тем, что метод toArray получает только

List 

и не

List<String>

поскольку дженерики - это только исходный код, они недоступны во время выполнения, поэтому они не могут определить, какой тип массива создавать.

использовать

toArray(new String[v2.size()]);

который выделяет правильный тип массива (String [] и правильного размера)

person MeBigFatGuy    schedule 16.04.2011
comment
@Калеб - неправда. Или, по крайней мере, это не первоначальная причина. Методы toArray существовали до того, как классы коллекций стали универсальными. - person Stephen C; 17.04.2011
comment
Это правильное решение, но не правильное объяснение. Вы не можете привести Object[] к Double[], потому что это особенность языка, не более того. Это не имеет отношения к дженерикам. Вы можете преобразовать Object в Double, предполагая, что это действительно Double. Логично, что вы могли бы сделать то же самое с массивом, но это просто не является частью языка. Если вы примените Object к Double, будет выполнена проверка во время выполнения, чтобы убедиться, что Object действительно ЯВЛЯЕТСЯ Double. Если вы приводите Double к Object, проверка во время выполнения не выполняется, так как Object находится в иерархии наследования Double. - person KyleM; 07.03.2013
comment
Когда я делаю это в IntelliJ, я получаю предупреждение о том, что лучше использовать toArray(new String[0]): в более старых версиях Java рекомендуется использовать массив предварительного размера, поскольку вызов отражения, необходимый для создания массива надлежащего размера, был довольно медленным. Однако после поздних обновлений OpenJDK 6 этот вызов был встроен, что сделало производительность версии с пустым массивом такой же, а иногда даже лучше. Также передача предварительно заданного массива опасна для параллельной коллекции, так как возможна гонка между вызовами size и toArray. - person Mikepote; 07.08.2019

Вы используете неправильный toArray()

Помните, что дженерики Java в основном представляют собой синтаксический сахар. На самом деле ArrayList не знает, что все его элементы являются строками.

Чтобы устранить проблему, вызовите toArray(T[]). В твоем случае,

String[] v3 = v2.toArray(new String[v2.size()]);

Обратите внимание, что обобщенная форма toArray(T[]) возвращает T[], поэтому результат не нужно приводить явно.

person Dilum Ranatunga    schedule 16.04.2011

String[] v3 = v2.toArray(new String[0]); 

также делает свое дело, обратите внимание, что вам даже не нужно больше приводить, как только методу будет присвоен правильный ArrayType.

person HopefullyHelpful    schedule 28.11.2019

String[] str = new String[list.size()];
str = (String[]) list.toArray(str);

Используйте так.

person MakNe    schedule 09.02.2019
comment
Пожалуйста! Отформатируйте код! Выделите все это, нажав ctrl + k, или добавьте ` перед первой буквой кода, а перед последней еще одну. Вы также можете выбрать {} в справке вверху при написании ответа! - person M.K; 09.02.2019