← Назад к вопросам
Как устроена внутренняя организация ArrayList в памяти с точки зрения хранения элементов?
2.0 Middle🔥 111 комментариев
#Коллекции
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Внутренняя организация ArrayList в памяти
ArrayList использует обычный Java массив для хранения элементов. Вот как это организовано.
Структура ArrayList
public class ArrayList<E> extends AbstractList<E> {
// Внутренний массив для хранения элементов
transient Object[] elementData;
// Актуальное количество элементов (size)
private int size;
// Константа по умолчанию
private static final int DEFAULT_CAPACITY = 10;
}
Как выглядит в памяти
ArrayList list = new ArrayList();
list.add("A");
list.add("B");
list.add("C");
В памяти Java Heap:
┌─────────────────────────────┐
│ ArrayList Object │
├─────────────────────────────┤
│ elementData ─────────┐ │
│ size = 3 │ │
│ ...other fields... │ │
└─────────────────────┼───────┘
│
↓
┌──────────────────────────────────┐
│ Object[] массив (capacity=10) │
├──────────────────────────────────┤
│ [0] → ref to "A" (String object) │
│ [1] → ref to "B" (String object) │ ← elementData[2]
│ [2] → ref to "C" (String object) │
│ [3] → null │
│ [4] → null │
│ [5] → null │
│ [6] → null │
│ [7] → null │
│ [8] → null │
│ [9] → null │
└──────────────────────────────────┘
Ключевые моменты
1. Хранятся ссылки (references), не сами объекты
ArrayList<String> list = new ArrayList<>();
list.add("Hello");
list.add("World");
// В elementData[0] хранится ссылка на String "Hello"
// В elementData[1] хранится ссылка на String "World"
// Сами строки находятся в другом месте в Heap
2. Тип хранения: Object[]
// Внутри ArrayList используется Object[]
// Это позволяет хранить любые типы (благодаря inheritance)
ArrayList<Integer> intList = new ArrayList<>();
intList.add(5);
// 5 автоматически оборачивается в Integer object
// В elementData хранится ref на Integer(5)
ArrayList<MyClass> myList = new ArrayList<>();
myList.add(new MyClass());
// В elementData хранится ref на MyClass object
3. Расположение в памяти
String Heap (где хранятся сами объекты):
┌──────────────────────────┐
│ String "A" (в String Pool)│
│ hash=1234, value=[......]│
└──────────────────────────┘
String "B" (в String Pool)
┌──────────────────────────┐
│ String "B" │
│ hash=5678, value=[......]│
└──────────────────────────┘
ArrayList elementData[]
┌──────────────────────┐
│ [0] → ref(String "A")│
│ [1] → ref(String "B")│
│ [2] → null │
└──────────────────────┘
Примитивные типы
// ❌ ArrayList<int> НЕ существует
// ArrayList<int> list = new ArrayList<>(); // Ошибка компиляции!
// ✅ Используем wrapper класс
ArrayList<Integer> list = new ArrayList<>();
list.add(5); // Автоматически: Integer.valueOf(5)
// В памяти
┌──────────────────────┐
│ Integer wrapper │
│ value = 5 │
└──────────────────────┘
^
│
└─ ref in elementData[0]
Удаление элемента
ArrayList<String> list = new ArrayList<>();
list.add("A"); // [0] → ref "A"
list.add("B"); // [1] → ref "B"
list.add("C"); // [2] → ref "C"
// size = 3, capacity = 10
list.remove(1); // Удаляем "B"
// После удаления:
┌──────────────────────┐
│ [0] → ref "A" │
│ [1] → ref "C" │ (сдвинулся с позиции 2)
│ [2] → null │ (обнулено для GC)
│ [3] → null │
└──────────────────────┘
// size = 2, capacity = 10 (не изменился!)
null элементы
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add(null); // ✅ Можно хранить null
list.add("C");
┌──────────────────────┐
│ [0] → ref "A" │
│ [1] → null │ (это валидный элемент)
│ [2] → ref "C" │
└──────────────────────┘
// size = 3 (null считается элементом!)
Особенности по версиям Java
Java 7+
// Type erasure - информация о типе стирается во время компиляции
ArrayList<String> list = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>();
// В runtime они одно и то же: ArrayList (без информации о типе)
// Проверка типа только во время компиляции
Получение внутреннего массива (рефлексия)
import java.lang.reflect.Field;
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
try {
// Получаем поле elementData
Field field = ArrayList.class.getDeclaredField("elementData");
field.setAccessible(true);
Object[] array = (Object[]) field.get(list);
System.out.println("Capacity: " + array.length); // 10
System.out.println("[0]: " + array[0]); // "A"
System.out.println("[1]: " + array[1]); // "B"
System.out.println("[2]: " + array[2]); // null
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
Сложность операций
Access by index [get(i)]: O(1) - прямой доступ к массиву
Insert at end [add(e)]: O(1) амортизированно
Insert at position [add(i, e)]: O(n) - нужен сдвиг элементов
Remove from end [remove(size-1)]: O(1)
Remove from start [remove(0)]: O(n) - нужен сдвиг элементов
Search [indexOf(e)]: O(n) - линейный поиск
Sort: O(n log n)
Резюме
ArrayList в памяти:
- Использует Object[] массив - хранит ссылки на объекты
- size - количество реальных элементов
- capacity - размер внутреннего массива
- Растёт на 50% когда capacity не достаточна
- Не уменьшается при удалении
- Ссылки, не значения - хранит refs, не сами объекты
- null элементы разрешены - это валидные элементы
- Type erasure - информация о типе стирается во время компиляции