Что такое arraylist в java
Структуры данных в картинках. ArrayList
Приветствую вас, хабралюди!
Взбрело мне в голову написать несколько статей, о том как реализованы некоторые структуры данных в Java. Надеюсь, статьи будут полезны визуалам (картинки наше всё), начинающим java-визуалам а также тем кто уже умеет писать new ArrayList(), но слабо представляет что же происходит внутри.
Сегодня поговорим о ArrayList-ах
ArrayList — реализует интерфейс List. Как известно, в Java массивы имеют фиксированную длину, и после того как массив создан, он не может расти или уменьшаться. ArrayList может менять свой размер во время исполнения программы, при этом не обязательно указывать размерность при создании объекта. Элементы ArrayList могут быть абсолютно любых типов в том числе и null.
Создание объекта
Только что созданный объект list, содержит свойства elementData и size.
Хранилище значений elementData есть ни что иное как массив определенного типа (указанного в generic), в нашем случае String[]. Если вызывается конструктор без параметров, то по умолчанию будет создан массив из 10-ти элементов типа Object (с приведением к типу, разумеется).
Вы можете использовать конструктор ArrayList(capacity) и указать свою начальную емкость списка.
Добавление элементов
Внутри метода add(value) происходят следующие вещи:
1) проверяется, достаточно ли места в массиве для вставки нового элемента;
2) добавляется элемент в конец (согласно значению size) массива.
Весь метод ensureCapacity(minCapacity) рассматривать не будем, остановимся только на паре интересных мест. Если места в массиве не достаточно, новая емкость рассчитывается по формуле (oldCapacity * 3) / 2 + 1. Второй момент это копирование элементов. Оно осуществляется с помощью native метода System.arraycopy(), который написан не на Java.
Ниже продемонстрирован цикл, поочередно добавляющий 15 элементов:
При добавлении 11-го элемента, проверка показывает что места в массиве нет. Соответственно создается новый массив и вызывается System.arraycopy().
После этого добавление элементов продолжается
Добавление в «середину» списка
Добавление элемента на позицию с определенным индексом происходит в три этапа:
1) проверяется, достаточно ли места в массиве для вставки нового элемента;
2) подготавливается место для нового элемента с помощью System.arraycopy();
3) перезаписывается значение у элемента с указанным индексом.
Как можно догадаться, в случаях, когда происходит вставка элемента по индексу и при этом в вашем массиве нет свободных мест, то вызов System.arraycopy() случится дважды: первый в ensureCapacity(), второй в самом методе add(index, value), что явно скажется на скорости всей операции добавления.
В случаях, когда в исходный список необходимо добавить другую коллекцию, да еще и в «середину», стоит использовать метод addAll(index, Collection). И хотя, данный метод скорее всего вызовет System.arraycopy() три раза, в итоге это будет гораздо быстрее поэлементного добавления.
Удаление элементов
Удалять элементы можно двумя способами:
— по индексу remove(index)
— по значению remove(value)
С удалением элемента по индексу всё достаточно просто
Сначала определяется какое количество элементов надо скопировать
затем копируем элементы используя System.arraycopy()
уменьшаем размер массива и забываем про последний элемент
При удалении по значению, в цикле просматриваются все элементы списка, до тех пор пока не будет найдено соответствие. Удален будет лишь первый найденный элемент.
Дополнение 1: Как верно заметил MikeMirzayanov, при удалении элементов текущая величина capacity не уменьшается, что может привести к своеобразным утечкам памяти. Поэтому не стоит пренебрегать методом trimToSize().
Итоги
— Быстрый доступ к элементам по индексу за время O(1);
— Доступ к элементам по значению за линейное время O(n);
— Медленный, когда вставляются и удаляются элементы из «середины» списка;
— Позволяет хранить любые значения в том числе и null;
— Не синхронизирован.
Ссылки
Пишите в комментариях пожелания/замечания и есть ли смысл продолжать.
Class ArrayList
— О, новый класс? Круто! И что он умеет делать?
— Начну с небольшой предыстории. Программистам очень не нравилось одно свойство массива – его размер нельзя изменять. Что делать, если нужно сохранить в массиве ещё три элемента, а свободное место только одно?
— Единственным решением проблемы нехватки места в массиве было создание массива очень большого размера, чтобы все элементы туда точно поместились. Но это часто приводило к нерациональному расходу памяти. Если чаще всего в массиве хранилось три элемента, но был хотя бы мизерный шанс, что там их будет 100, приходилось создавать массив на 100 элементов.
— И что же придумали программисты?
— Они написали класс ArrayList (списочный массив), который выполнял ту же работу, что и Array (массив), но мог изменять свой размер.
— Интересный ход. И как же они это сделали?
Array | ArrayList |
---|---|
Создание контейнера элементов | |
Получение количества элементов | |
Взятие элемента из массива/коллекции | |
Запись элемента в массив |
— И в чем же преимущество ArrayList? Как по мне, так код стал длиннее.
— Во-первых, ArrayList поддерживает несколько дополнительных действий, которые очень часто приходится делать программистам во время работы, и которых нет у массива. Например – вставка и удаление элементов из середины массива, и чтобы не оставалось дырок.
— Во-вторых, изменение размера: когда нужно записать во внутренний массив ещё один элемент, а свободного места там нет, то внутри ArrayList делается вот что:
а) создаётся ещё один массив, в полтора раза больше размера внутреннего массива, плюс один элемент.
б) все элементы из старого массива копируются в новый массив.
в) новый массив сохраняется во внутренней переменной объекта ArrayList, старый массив объявляется мусором (мы просто перестаём хранить на него ссылку).
Что такое ArrayList в Java
Вы уже умеете создавать массивы в Java? Тогда самое время узнать что такое Arraylist. Ну что ж, поехали!
Допустим, Вы работаете программистом на компанию, которая осуществляет доставку товаров по всему миру. И Вам необходимо сохранить список городов, в которые осуществляется доставка.
Вы это можете сделать 2 способами:
1. С помощью обычного массива
2. С помощью Arraylist
1. С ПОМОЩЬЮ ОБЫЧНОГО МАССИВА
Создаем обычный массив с именем deliveryCities. В фигурных скобках прописываем значения элементов массива, то есть названия городов. Например:
В результате, будет создан массив deliveryCities на 4 элемента. И если мы заходим получить 3-й элемент массива – мы напишем deliveryCities[2], поскольку 3-й элемент имеет индекс 2. Таким образом мы можем создать массив из элементов любого типа, после чего можем работать с этими элементами.
Но что, если мы хотим добавить еще один город для доставки, например, London?
И вот Вам мой ответ: «Так сделать не получится! Потому что в Java нет возможности изменять длину массивов. А это значит, что если Вы изначально создали массив на 4 элемента, значит уже этот массив будет всегда на 4 элемента.»
Решение будет выглядеть так:
2. С ПОМОЩЬЮ ARRAYLIST
Так что же такое Arraylist? Говоря простым и понятным языком, ArrayList – это список, который очень похож на массив за исключением того, что он имеет произвольную длину и целый ряд методов, которые позволяют добавлять, удалять, заменять элементы списка в любое время и в любом месте.
А это значит, что Вы можете, например, сначала создать Arraylist на 4 элемента, а потом взять и добавить еще 7 элементов, а потом удалить 2 элемента, а потом снова добавить 15 элементов и т.д. Вы поняли идею, Arraylist, как резиновый, его можно увеличивать или уменьшать безо всяких проблем.
Работать с ArrayList очень и очень просто
Во-первых, как и в случае с массивами, нужно создать список. Создать список можно несколькими способами. Наиболее распространенным способом является следующая структура:
ArrayList в Java
Что такое класс ArrayList?
Что хранит ArrayList?
Конструкторы ArrayList
ArrayList()
Пустой конструктор с начальной емкостью внутреннего массива = 10.
_c)»>ArrayList(Collection c)
Конструктор принимает другую коллекцию, создавая новый массив с элементами переданной коллекции:
Порядок элементов в новом списке будет совпадать с исходным.
ArrayList(int initialCapacity)
В качестве параметра конструктора выступает значения начального размера внутреннего массива.
Если в массиве, который лежит в основе ArrayList, закончилось место при добавлении новых элементов, создается новый массив большего размера, и данные копируются в него. Если при написании кода заранее известно, что в массиве будет обрабатываться большое количество элементов, в целях оптимизации следует указать большее значение.
Методы ArrayList
Ниже представлены основные методы ArrayList.
add(E e)
add(int index, E element)
Добавляет элемент element в позицию index. При добавлении происходит сдвиг всех элементов справа от указанного индекса на 1 позицию вправо:
Очень полезен, когда нужно вставить элемент в произвольное место списка, однако для частых операций вставки в начало и середину ArrayList может оказаться не очень удачным выбором — следует изучить LinkedList.
_collection)»>addAll(Collection collection)
Добавление всех элементов коллекции collection в список в порядке их расположения в collection.
_collection)»>addAll(int index, Collection collection)
Методы addAll() также возвращают boolean-результат добавления элементов.
clear()
Удаление всех элементов из списка.
Возвращает объект-копию массива:
При клонировании создается новый независимый объект. В примере показано, как очищение клонированного объекта не сказалось на составе его клона.
contains(Object o)
ensureCapacity(int minCapacity)
Этот метод полезен, когда возникает потребность вместить большое количество элементов в несколько итераций. Например, при создании списка емкость его внутреннего массива — 10. При загрузке данных по сети они обрабатываются асинхронно порциями и результаты помещаются в массив. Если ожидается доставка 10 000 элементов, может быть неэффективно просто добавлять эти данные каждый раз: достаточно будет в начале обработки вызвать метод ensureCapaciry(10000) и записывать туда данные по мере необходимости.
_action)»>forEach(Consumer action)
Обработать в цикле ArrayList можно стандартными способами, цикл for:
В классе ArrayList есть метод для обработки каждого элемента, который называется также, forEach. В качестве аргумента передается реализация интерфейса Consumer, в котором нужно переопределить метод accept():
Метод accept принимает в качестве аргумента очередной элемент того типа, который хранит в себе ArrayList. Пример для Integer:
Метод action() будет выполнен для каждого элемента.
get(int index)
Возвращает элемент, который расположен в указанной позиции списка.
Это основной метод получения элемента из списка, время извлечения элемента по индексу всегда будет одинаковым, независимо от размера ArrayList.
indexOf(Object o)
isEmpty()
Метод возвращает true, если список пустой, false в обратном случае.
iterator()
Возвращает итератор для списка для последующего использования в цикле или при любой другой обработке.
Итератор для ArrayList — fail-fast. Это значит, что если коллекция изменится во время итерации, будет выброшено исключение ConcurrentModificationException. Подробнее об fail-fast и его противоположности fail-safe можно почитать здесь.
lastIndexOf(Object o)
remove(int index)
Удаление элемента в указанной позиции индекса. После удаления сдвигает все элементы влево для заполнения освободившегося пространства.
remove(Object o)
_c)»>removeAll(Collection c)
set(int index, E element)
size()
Лучший способ (практически единственный) для того, чтобы узнать размер массива.
_c)»>sort(Comparator c)
toArray()
Превращает список в фиксированный массив. Обратите внимание, что метод возвращает массив объектов ( Object[] ). Если необходимо привести список в массив объектов определенного типа, в качестве параметра в метод можно передать массив, куда будут перемещены элементы списков.
Методы ArrayList в Java изучаются на курсе JavaRush. Первое знакомство происходит на седьмом уровне квеста Java Syntax, на лекции “Класс ArrayList”. На этом же уровне есть подборки задач — раз и два, в которых нужно использовать методы ArrayList, приведены дополнительные примеры работы с ArrayList и дженериками, а также объясняется разница между ArrayList и LinkedList. Это обширная тема изучения, поэтому в том или ином виде к Arraylist в Java (методы этого класса — лишь часть всего массива знаний, в который стоит углубиться) на курсе возвращаются и на следующих уровнях обучения — Core, Collections, Multithreading. Мы верим, что ежедневная практика написания кода — главный ключ к успеху в программировании. Поэтому JavaRush на 80% состоит из практических задач, мини проектов, задач-игр. Все это — сотни часов кодинга, которые помогут прокачать скилл.
Коллекции в Java: ArrayList
1. Класс ArrayList
Чтобы полностью понять, как устроены коллекции и все нюансы их работы, нужно сначала изучить ООП, интерфейсы, наследование, азы многопоточности и многое другое.
Предыстория
Начну с небольшой предыстории. Программистам очень не нравилось одно свойство массива — его размер нельзя изменять. Что делать, если нужно сохранить в массиве ещё три элемента, а свободное место только одно?
Единственным решением проблемы нехватки места в массиве было создание массива очень большого размера, чтобы все элементы туда точно поместились. Но это часто приводило к нерациональному расходу памяти. Если обычно в массиве хранилось два-три элемента, но был хотя бы мизерный шанс, что там их будет 100, приходилось создавать массив на 100 элементов.
И что же придумали программисты? Они написали класс ArrayList (массив-список), который выполнял ту же работу, что и Array (массив), но мог изменять свой размер.
Класс ArrayList
Само название ArrayList происходит из двух слов: Array + List. Array — это массив, а List — список.
У класса ArrayList отсутствуют все недостатки, которые есть у массивов. Он умеет:
2. Создание объекта ArrayList
Тип у переменной имя составной — состоит аж из двух типов: сначала указывается тип коллекции, а в треугольных скобках указывается тип элементов, которые эта коллекция хранит.
Код | Описание |
---|---|
Список целых чисел | |
Список строк | |
Список вещественных чисел |
3. Операции с ArrayList
Изначально длина только что созданного списка равна нулю: он содержит 0 элементов. Если в список добавить один элемент, его длина увеличится на 1. Если удалить добавленный элемент, опять уменьшится до нуля.
Более подробно можно узнать о методах класса ArrayList из таблицы:
Данные методы позволяют делать со списком практически все возможные операции: менять элементы местами, добавлять элементы, удалять элементы. Можно даже очистить список одной командой или преобразовать список в массив.