Какова начальная ёмкость (capacity) ArrayList по умолчанию в Java и как она изменяется?

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

Ответ

Начальная ёмкость (capacity) внутреннего массива ArrayList при создании через конструктор без параметров равна 0, а не 10, начиная с Java 8. Массив создаётся лениво, при первом добавлении элемента.

Механизм работы:

  1. Конструктор ArrayList(): Инициализирует внутренний массив elementData пустой константой DEFAULTCAPACITY_EMPTY_ELEMENTDATA.
    // Java 8+
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; // {} (пустой массив)
    }
  2. Первое добавление (add(E e)): При первом вызове add() проверяется, является ли массив пустой константой. Если да, то ёмкость увеличивается до значения DEFAULT_CAPACITY, которое равно 10.
    private static final int DEFAULT_CAPACITY = 10;
  3. Последующее увеличение: Когда внутренний массив заполняется, его ёмкость увеличивается по формуле newCapacity = oldCapacity + (oldCapacity >> 1), что примерно равно увеличению в 1.5 раза.

Конструкторы для явного указания ёмкости:

// Создаёт ArrayList с начальной ёмкостью 20
ArrayList<String> listWithCapacity = new ArrayList<>(20);

// Создаёт список, инициализированный другой коллекцией.
// Начальная ёмкость равна размеру переданной коллекции.
ArrayList<String> listFromCollection = new ArrayList<>(someOtherList);

Практические рекомендации:

  • Избегайте дефолтного конструктора, если заранее известен примерный размер коллекции. Указание начальной ёмкости предотвращает многократные дорогостоящие операции копирования массива при росте.
  • size() vs capacity(): size() возвращает количество элементов в списке, а capacity() — длину внутреннего массива (этот метод private, но его логику можно понять).