Ответ
ArrayList — это реализация интерфейса List на основе динамически изменяемого массива. Это наиболее часто используемая коллекция в Java.
Ключевые характеристики:
- Основа: Динамический массив (
Object[]). - Доступ по индексу: O(1) — очень быстрый.
- Вставка в конец: Амортизированная O(1), но может потребовать увеличения массива.
- Вставка/удаление в середину: O(n) — требует сдвига элементов.
- Порядок: Сохраняет порядок добавления элементов.
- Дубликаты и null: Разрешает и то, и другое.
Базовые операции:
// Создание
List<String> list = new ArrayList<>();
List<Integer> sizedList = new ArrayList<>(100); // Начальная capacity
// Добавление
list.add("A"); // В конец
list.add(0, "B"); // По индекту (O(n) для середины!)
// Доступ
String element = list.get(2); // O(1)
// Удаление
list.remove(0); // По индекту (O(n) для середины!)
list.remove("A"); // По значению (O(n))
// Итерация
for (String s : list) { /* ... */ }
list.forEach(System.out::println);
Внутреннее устройство и производительность:
// При создании ArrayList() capacity по умолчанию = 10
// При добавлении элемента, если массив заполнен:
// 1. Создается новый массив размером ~ в 1.5 раза больше (oldCapacity + (oldCapacity >> 1))
// 2. Все элементы копируются в новый массив (System.arraycopy)
// Это операция O(n), но амортизированная стоимость добавления остается O(1)
| Сравнение с LinkedList: | Критерий | ArrayList | LinkedList |
|---|---|---|---|
| Структура | Динамический массив | Двусвязный список | |
| Получение по индексу | O(1) | O(n) | |
| Вставка в начало | O(n) | O(1) | |
| Вставка в конец | Амортизированная O(1) | O(1) | |
| Удаление из середины | O(n) | O(n) (но быстрее, если уже есть итератор) | |
| Память | Меньше (только данные + overhead массива) | Больше (данные + 2 ссылки на узел) |
Многопоточность:
-
ArrayListне синхронизирован. Для использования в многопоточных сценариях:// 1. Синхронизированная обертка List<String> syncList = Collections.synchronizedList(new ArrayList<>()); // 2. CopyOnWriteArrayList (для read-heavy workloads) List<String> copyOnWriteList = new CopyOnWriteArrayList<>();
Рекомендации по использованию:
- Используйте
ArrayListпо умолчанию для списков, если не нужны специфические возможности других реализаций. - Указывайте начальную capacity, если известен примерный размер списка, чтобы избежать лишних расширений массива.
- Используйте
LinkedListтолько если нужны частые вставки/удаления в начало списка или работа черезIterator. - Для частого поиска по значению используйте
HashSetилиHashMap.