Почему Java Collection <E>.toArray() возвращает объект [], а не E []?
До генерирования Java, Collection.toArray()
не имел способа узнать, какой тип массива ожидал разработчик (особенно для пустой коллекции). Насколько я понимаю, это было основным аргументом в пользу идиомы collection.toArray(new E[0])
.
С generics Collection<E>.toArray()
может возвращать массив, полный экземпляров E
и/или его специализаций. Интересно, почему тип возврата по-прежнему равен Object[]
, а не E[]
. На мой взгляд, возврат E[]
вместо Object[]
не должен нарушать существующий код.
Смотрите: Collection.toArray()
, Collection.toArray(T[])
и связанная с этим тема java: (String []) List.toArray() предоставляет ClassCastException
Ответы
Ответ 1
Это очень хороший вопрос. Ответ заключается в том, что дженерики также называются "стираниями". Это не просто имя. Информация, закодированная дженериками, используется только во время компиляции, а затем удаляется. Таким образом, JVM даже не знает этот общий тип E
, поэтому он не может создать массив E[]
.
Другой метод toArray(T[] a)
получает информацию о типе из аргумента во время выполнения. По этой причине прототип этого метода <T> T[] toArray(T[] a)
: он получает массив типа T и может возвращать массив типа T. Тип передается как параметр.
Ответ 2
"Стирание типа" является лишь частичным объяснением: ни метод Collection
, ни его toArray()
не имеют никакой информации о E
во время выполнения.
Кроме того, из-за обратной совместимости, Collection.toArray()
должен возвращать Object[]
. До Java 1.5 не было способа узнать общий тип для коллекции, поэтому это был единственный разумный дизайн API.
Ответ 3
@Lukas, относительно: "новый E []"
Новый E [0] поднял ошибку компилятора, как вы, вероятно, ожидали. Обходной путь, который я нашел, это:
final E [] returnArray = (E []) events.toArray(новое событие [events.size()]);
N.B. код находится в классе шаблона Listener < E extends Event > .
В моем обходном пути тип стирания - это и проблема, и решение. Приведение к (E []) безопасно, потому что его точный тип стирается до Event []. Единственный недостаток, который я вижу, - это предупреждение компилятора о "непроверенных или небезопасных операциях" (что, очевидно, в данном случае приведение не выполняется при стирании типа).
@Lukas, относительно обратной совместимости
Я не вижу большой проблемы с обратной совместимостью. Создание особого типа возвращаемого значения - это не то же самое, что сделать тип аргумента более особенным.
Другими словами, исходный код, который до сих пор ожидал, что Collection.toArray() возвратит Object [], должен с полным удовольствием получить E [].
И что касается байтового кода, Object [] и E [] в любом случае одинаковы из-за стирания типа.