«1. Обзор

В этом руководстве мы рассмотрим различные способы расширения массива Java.

Так как массивы представляют собой непрерывный блок памяти, ответ может быть неочевидным, но давайте разберем его сейчас.

2. Использование Arrays.copyOf

Сначала рассмотрим Arrays.copyOf. Мы скопируем массив и добавим в копию новый элемент:

public Integer[] addElementUsingArraysCopyOf(Integer[] srcArray, int elementToAdd) {
    Integer[] destArray = Arrays.copyOf(srcArray, srcArray.length + 1);
    destArray[destArray.length - 1] = elementToAdd;
    return destArray;
}

Метод работы Arrays.copyOf заключается в том, что он берет srcArray и копирует количество элементов, указанное в аргументе длины, в новый массив, который он внутренне создает. Размер нового массива — это аргумент, который мы предоставляем.

Следует заметить, что когда аргумент длины больше размера исходного массива, Arrays.copyOf заполнит дополнительные элементы в целевом массиве нулевым значением.

В зависимости от типа данных поведение заливки будет разным. Например, если мы используем примитивные типы данных вместо Integer, то лишние элементы заполняются нулями. В случае char Arrays.copyOf заполнит дополнительные элементы нулевым значением, а в случае логического значения — ложным.

3. Использование ArrayList

Следующий способ, который мы рассмотрим, это использование ArrayList.

Сначала мы преобразуем массив в ArrayList, а затем добавим элемент. Затем мы преобразуем ArrayList обратно в массив:

public Integer[] addElementUsingArrayList(Integer[] srcArray, int elementToAdd) {
    Integer[] destArray = new Integer[srcArray.length + 1];
    ArrayList<Integer> arrayList = new ArrayList<>(Arrays.asList(srcArray));
    arrayList.add(elementToAdd);
    return arrayList.toArray(destArray);
}

Обратите внимание, что мы передали srcArray, преобразовав его в коллекцию. srcArray заполнит базовый массив в ArrayList.

Также следует отметить, что мы передали целевой массив в качестве аргумента toArray. Этот метод скопирует базовый массив в destArray.

4. Использование System.arraycopy

Наконец, мы рассмотрим System.arraycopy, который очень похож на Arrays.copyOf:

public Integer[] addElementUsingSystemArrayCopy(Integer[] srcArray, int elementToAdd) {
    Integer[] destArray = new Integer[srcArray.length + 1];
    System.arraycopy(srcArray, 0, destArray, 0, srcArray.length);
    destArray[destArray.length - 1] = elementToAdd;
    return destArray;
}

Один интересный факт заключается в том, что Arrays.copyOf внутри использует этот метод.

Здесь мы можем заметить, что мы копируем элементы из srcArray в destArray, а затем добавляем новый элемент в destArray.

5. Производительность

Во всех решениях есть одна общая черта: нам так или иначе приходится создавать новый массив. Причина этого кроется в том, как массивы распределяются в памяти. Массив содержит непрерывный блок памяти для сверхбыстрого поиска, поэтому мы не можем просто изменить его размер.

Это, конечно, влияет на производительность, особенно для больших массивов. Вот почему ArrayList перераспределяет память, эффективно уменьшая количество раз, которое JVM требуется для перераспределения памяти.

Но если мы делаем много вставок, массив может быть не правильной структурой данных, и нам следует рассмотреть LinkedList.

6. Заключение

В этой статье мы рассмотрели различные способы добавления элементов в конец массива.

И, как всегда, весь код доступен на GitHub.