Как динамически расширяется ArrayList в Java?

«Как динамически расширяется ArrayList в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

ArrayList динамически расширяется за счет изменения размера своего внутреннего массива (Object[] elementData).

Механизм увеличения емкости:

  1. При добавлении элемента (например, через add()) проверяется, достаточно ли свободных ячеек в массиве.
  2. Если емкости недостаточно, запускается процесс grow():
    • Создается новый массив большего размера.
    • Все элементы копируются из старого массива в новый с помощью Arrays.copyOf.
    • Ссылка elementData начинает указывать на новый массив.
    • Старый массив становится доступным для сборщика мусора.

Формула увеличения: По умолчанию новый размер вычисляется как newCapacity = oldCapacity + (oldCapacity >> 1). Это увеличение в 1.5 раза (побитовый сдвиг вправо на 1 равен целочисленному делению на 2).

Пример:

// Начальная емкость по умолчанию — 10
ArrayList<Integer> list = new ArrayList<>();

// Добавление 11-го элемента вызовет расширение
for (int i = 0; i < 11; i++) {
    list.add(i); // При i == 10 произойдет grow()
}

Почему так сделано? Увеличение в 1.5 раза — это компромисс между производительностью (слишком частое копирование) и расходом памяти (слишком большой неиспользуемый запас). Начальную емкость можно задать конструктором ArrayList(int initialCapacity), чтобы минимизировать количество расширений, если известен примерный размер данных.