← Назад к вопросам

Что такое ArrayList?

1.3 Junior🔥 191 комментариев
#Коллекции и структуры данных

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое ArrayList?

ArrayList — это реализация динамического массива (resizable-array) в языке Java, которая входит в состав коллекций (Collections Framework) и реализует интерфейс List. В отличие от обычного массива, который имеет фиксированную длину после создания, ArrayList может автоматически увеличивать свою вместимость при добавлении новых элементов, что делает его чрезвычайно удобным для работы с наборами данных, размер которых заранее неизвестен или может изменяться.

Ключевые особенности ArrayList:

  • Динамическое изменение размера: Внутри ArrayList использует обычный массив для хранения элементов. Когда массив заполняется, ArrayList создаёт новый массив большего размера (обычно в 1.5 раза, начиная с Java 8) и копирует в него все элементы из старого.
  • Индексированный доступ: Поддерживает быстрый доступ к элементам по индексу за константное время O(1), так как операция сводится к обращению к внутреннему массиву.
  • Реализация интерфейса List: Гарантирует сохранение порядка добавления элементов и позволяет хранить дубликаты.
  • Не является синхронизированным: Как и большинство коллекций, ArrayList не потокобезопасен. Если несколько потоков изменяют его одновременно, необходимо использовать внешнюю синхронизацию или класс Collections.synchronizedList().
  • Допускает null значения: Можно добавлять null элементы.

Основные операции и примеры кода

1. Создание и добавление элементов

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        // Создание ArrayList (рекомендуется использовать интерфейс List слева)
        List<String> fruits = new ArrayList<>();

        // Добавление элементов в конец списка
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");
        fruits.add(null); // Допустимо

        // Добавление элемента по индексу (со сдвигом остальных вправо)
        fruits.add(1, "Mango");

        System.out.println(fruits); // [Apple, Mango, Banana, Orange, null]
    }
}

2. Доступ, изменение и удаление элементов

// Получение элемента по индексу (быстрая операция O(1))
String fruit = fruits.get(0); // "Apple"

// Изменение элемента по индексу
fruits.set(2, "Cherry"); // Заменяет "Banana" на "Cherry"

// Удаление элемента по индексу (остальные элементы сдвигаются влево)
fruits.remove(0); // Удалит "Apple"

// Удаление элемента по значению (первого вхождения)
fruits.remove("Cherry"); // Удалит "Cherry"

// Проверка наличия элемента и размера списка
boolean hasApple = fruits.contains("Apple");
int size = fruits.size();
boolean isEmpty = fruits.isEmpty();

3. Итерация по элементам

// 1. Классический цикл for (если нужен индекс)
for (int i = 0; i < fruits.size(); i++) {
    System.out.println(fruits.get(i));
}

// 2. Улучшенный цикл for-each
for (String f : fruits) {
    System.out.println(f);
}

// 3. Использование итератора (позволяет удалять элементы во время обхода)
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
    String f = iterator.next();
    if (f == null) {
        iterator.remove(); // Безопасное удаление
    }
}

Внутреннее устройство и производительность

Под капотом ArrayList хранит элементы в массиве Object[] elementData. Это определяет его сильные и слабые стороны с точки зрения Big O notation:

  • add(E e) (в конец) — O(1) амортизированное время. В худшем случае, когда массив полон и требуется его увеличение и копирование, — O(n).
  • add(int index, E element) (в середину) — O(n), так как требует сдвига всех последующих элементов.
  • get(int index)O(1), прямое обращение по индексу в массиве.
  • remove(int index)O(n), из-за необходимости сдвига элементов.
  • contains(Object o)O(n) в общем случае, так как требует последовательного поиска по всему списку. Для быстрого поиска по значению лучше использовать HashSet.

Важные практические аспекты для Android

  1. Инициализация с начальной ёмкостью: Если вы заранее знаете примерное количество элементов, укажите его при создании. Это предотвратит многократные дорогостоящие операции копирования массива при его росте.

    // Создаём ArrayList, который изначально может хранить 100 элементов без ресайза
    List<User> users = new ArrayList<>(100);
    
  2. Потокобезопасность: В Android, где асинхронные операции и потоки — обычное дело, использование простого ArrayList из нескольких потоков без синхронизации приведёт к ошибкам или ConcurrentModificationException. Для многопоточных сценариев рассмотрите CopyOnWriteArrayList (если чтений много, а записей мало) или синхронизацию.

  3. Передача между компонентами: В Android ArrayList часто используется для передачи данных в адаптеры RecyclerView.Adapter, в Intent (как ParcelableArrayList), или для хранения результатов сетевых запросов.

Заключение

ArrayList — это фундаментальная и наиболее часто используемая структура данных в Java и Android разработке. Его сила — в простоте, эффективности доступа по индексу и автоматическом управлении размером. Однако разработчик должен осознанно выбирать его, учитывая сценарий использования: частые вставки/удаления в середину списка требуют других структур (например, LinkedList), а необходимость потокобезопасности — дополнительных мер синхронизации или выбора альтернативных коллекций.

Что такое ArrayList? | PrepBro