Почему Java Collection<E>.toArray () возвращает объект [], а не E[]?

До обобщения Java, Collection.toArray() не было никакого способа узнать, какой тип массива ожидал разработчик (особенно для пустой коллекции). Насколько я понимаю, это было основным обоснованием идиомы collection.toArray(new E[0]),

С дженериками, Collection<E>.toArray() может только вернуть массив, полный экземпляров E и / или его специализации. Интересно, почему тип возвращаемого значения по-прежнему Object[] скорее, чем E[], На мой взгляд, возвращение E[] вместо Object[] не должен нарушать существующий код.

Увидеть: Collection.toArray(), Collection.toArray(T[]) и связанная тема Java: (String[])List.toArray() дает ClassCastException

3 ответа

Это очень хороший вопрос. Ответ в том, что дженерики также называются "стиранием". Это не просто имя. Информация, закодированная генериками, используется только во время компиляции, а затем удаляется. Итак, JVM даже не знает этот универсальный тип Eпоэтому он не может создать массив E[],

Другой метод toArray(T[] a) получает информацию о типе из аргумента во время выполнения. По этой причине прототип этого метода <T> T[] toArray(T[] a): он получает массив типа T и может возвращать массив типа T. Тип передается как параметр.

"Стирание типа" является лишь частичным объяснением: ни Collectionни его toArray() Метод имеет любую информацию о E во время выполнения.

Это также из-за обратной совместимости, что Collection.toArray() должен еще вернуться Object[], До Java 1.5 не было никакого способа узнать универсальный тип для коллекции, так что это был единственный разумный дизайн API.

@Lukas, относительно: "новый E[]"

Новый E[0] вызвал ошибку компилятора, как вы, вероятно, ожидали. Обходной путь, который я нашел:

final E[] returnArray = (E[]) events.toArray (new Event [events.size ()]);

NB код находится в шаблоне класса Listener.

В моем обходном решении стирание типов - это и проблема, и решение. Приведение к (E[]) безопасно, поскольку его точный тип стирается в Event[]. Единственным недостатком, который я вижу, является предупреждение компилятора о "непроверенных или небезопасных операциях" (которые, очевидно, в данном случае не приводят к стиранию типа).

@Lukas, относительно обратной совместимости

Я не вижу большой проблемы с обратной совместимостью. Делать возвращаемый тип более особенным - это не то же самое, что делать тип аргумента более особенным.

Другими словами, исходный код, который до сих пор ожидал, что Collection.toArray() вернет Object[], должен быть счастлив получить вместо него E[].

А что касается байт-кода, Object[] и E[] в любом случае одинаковы из-за стирания типа.

Другие вопросы по тегам