Это:
add(i.toArray(new Animal[i.size()]))
List.toArray возвращает Object[]
, независимо от типа аргумента в списке: даже если вы могли бы написать new List<String>().toArray()
, вы получите Object[]
. Тем не менее, version of toArray that takes an array to fill возвращает массив с правильным типом: если вы пишете new List<String>().toArray(new String[0])
, вы получите String[]
. Обратите внимание, что размер массива, который вы передаете, даже не должен соответствовать размеру списка, хотя это хорошая практика, чтобы обеспечить его выполнение.
Это, в конечном счете, из-за слегка сложной функции дженериков. На первый взгляд, вы можете подумать, что String[]
и List<String>
означают похожие вещи для их базовых типов - один представляет собой массив строк, другой - список строк.
Однако они на самом деле очень разные.
Массив является примитивным языком и имеет свой тип, запеченный в нем. Если вы взяли шестнадцатеричный редактор и посмотрели на экземпляр массива в памяти в JVM, вы могли бы найти (где-то рядом) запись о типе объектов, которые она хранит. Это означает, что если вы берете экземпляр массива какого-либо неизвестного типа компонента, вы можете find out what that type is. И наоборот, это означает, что если вы собираетесь create an instance of an array, вам нужно знать, какой тип компонента вы хотите.
List
, с другой стороны, использует дженерики, которые в Java, реализуется с type erasure, что означает, что, грубо говоря, это то, что существует в компиляторе, но не во время выполнения (компилятор может проверить, что вы Правильно, но JVM не может). Это приводит к простой и эффективной реализации (достаточно простой, чтобы быть добавленным к предиповым Java, не изменяя JVM), но у него есть некоторые недостатки - в частности, что во время выполнения нет способа рассказать, что аргумент типа в любом конкретном экземпляре универсального класса, поскольку аргументы типа существуют только в компиляторе. Потому что до экземпляра List
обрабатывать toArray()
, единственное, что он может сделать, это создать Object[]
. Он просто не знает более конкретного типа для использования.
Один способа смотреть на это, что массивы имеют аргумент типа как часть их класса, в то время как List
s имеет аргумент типа как часть их типа, и так как объекты имеют классы, но переменные имеют тип, вы не можете получить аргумент типа List
от объекта, только из переменной, удерживающей объект (как в сторону, вы также не можете получить аргумент типа массива из переменной, содержащей массив (рассмотрите Object[] array = new String[0];
), но это не имеет большого значения, потому что переменная позволяет вам захватить объект - если это не пусто).
Кипятить это до кода, проблема:
public <E> E[] createSimilarlyTypedArray(List<E> list) {
Class<E> componentType = list.???; // there is no way to do this
return Arrays.newInstance(componentType, list.size());
}
Я не могу понять вопрос. Вы создали свой собственный метод'add (Animal ...) ', но вы вызываете ArrayList.add (Object), а не свой собственный. Почему это? Пожалуйста, отредактируйте вопрос в контексте кода. Этот блок кода внутри вашего метода «адд»? Если ваша единственная проблема заключается в том, что вы не можете бросить объект [] в Animal [], то выполните ответ @Tom. – aalku
Просто заметьте на будущее: если у вас есть ошибка компилятора, скопируйте полное сообщение об ошибке, а также строки исходного кода, относящиеся к этому сообщению. –