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 во время выполнения, поскольку дженерики были удалены.)