Java List toArray (T [] a) реализация
Я просто смотрел на метод, определенный в интерфейсе List:
Возвращает массив, содержащий все элементы в этом списке в правильном порядке; тип выполнения возвращаемого массива - тип указанного массива. Если список соответствует указанному массиву, он возвращается в нем. В противном случае новый массив выделяется типом среды выполнения указанного массива и размером этого списка. Если список соответствует указанному массиву с запасными местами (т.е. Массив имеет больше элементов, чем список), элемент в массиве сразу же после окончания коллекции устанавливается в нуль. Это полезно при определении длины списка только в том случае, если вызывающий абонент знает, что список не содержит никаких нулевых элементов.
<T> T[] toArray(T[] a);
И мне просто интересно, почему это реализовано таким образом, в основном, если вы передадите ему массив с длиной < в list.size(), он просто создаст новый и вернет его. Поэтому создание нового объекта Array в параметре метода бесполезно.
Кроме того, если вы передадите ему массив достаточно долго, используя размер списка, если возвращает тот же объект с объектами - на самом деле нет смысла возвращать его, поскольку он является одним и тем же объектом, но нормально для ясности.
Проблема в том, что я думаю, что это способствует немного неэффективному коду, на мой взгляд toArray должен просто получить класс и просто вернуть новый массив с содержимым.
Есть ли причина, почему он не закодирован таким образом?
Ответы
Ответ 1
Как упоминалось другими, существует несколько разных причин:
- Вам нужно каким-то образом передать тип, и передача в массиве указанного типа не является необоснованным способом сделать это. По общему признанию, было бы неплохо, если бы была версия, которую вы передаете в классе того типа, который вы хотите, для скорости.
- Если вы хотите повторно использовать свой массив, вы можете продолжать передавать его в одном и том же порядке, а не каждый раз создавать новый. Это может сэкономить время и память, а также проблемы с GC, если вам нужно сделать это много раз.
Ответ 2
357 public <T> T[] toArray(T[] a) {
358 if (a.length < size)
359 // Make a new array of a runtime type, but my contents:
360 return (T[]) Arrays.copyOf(elementData, size, a.getClass());
361 System.arraycopy(elementData, 0, a, 0, size);
362 if (a.length > size)
363 a[size] = null;
364 return a;
365 }
Может быть, у него есть тип времени выполнения?
Из wiki:
Следовательно, создание экземпляра Java класс параметризованного типа невозможно, потому что требует вызова конструктора, который недоступен, если тип неизвестно.
Ответ 3
Скорее всего, это позволит вам повторно использовать массивы, поэтому вы в основном избегаете (относительно дорогого) распределения массива для некоторых случаев использования. Еще одно гораздо меньшее преимущество заключается в том, что вызывающий может создавать массив немного более эффективно, поскольку toArray() должен использовать метод java.lang.reflect.Array.newInstance.
Ответ 4
Этот метод является задержкой с pre-1.5 Java. Вот ссылка на javadoc
Тогда это был единственный способ конвертировать список в reifiable array.
Это неясный факт, но, хотя вы можете хранить что-либо в массиве Object [], вы не можете использовать этот массив для более конкретного типа, например.
Object[] generic_array = { "string" };
String[] strings_array = generic_array; // ClassCastException
По-видимому, более эффективный List.toArray()
делает именно это, он создает общий массив Object
.
Прежде чем генерировать Java файлы, единственным способом сделать перенос типа безопасным является наличие этой группы:
String[] stronglyTypedArrayFromList ( List strings )
{
return (String[]) strings.toArray( new String[] );
// or another variant
// return (String[]) strings.toArray( new String[ strings.size( ) ] );
}
К счастью, дженерики сделали эти махинации устаревшими. Этот метод остался там, чтобы обеспечить обратную совместимость с кодом pre 1.5.
Ответ 5
Мое предположение заключается в том, что если вы уже знаете конкретный тип T
в точке, которую вы вызываете toArray(T[])
, она более эффективна, чтобы просто объявить массив того, что есть, чем сделать вызов реализации List
Arrays.newInstance()
для вас - плюс во многих случаях вы можете повторно использовать массив.
Но если это вас раздражает, достаточно легко написать полезный метод:
public static <E> E[] ToArray(Collection<E> c, Class<E> componentType) {
E[] array = (E[]) Array.newInstance(componentType, c.size());
return c.toArray(array);
}
(Обратите внимание, что нет способа написать <E> E[] ToArray(Collection<E> c)
, потому что нет способа создать массив E
во время выполнения без объекта Class
и не получить объект Class
для E
во время выполнения, поскольку дженерики были удалены.)