JavaRush /Курсы /Java Syntax Pro /Знакомство с коллекцией LinkedList

Знакомство с коллекцией LinkedList

Java Syntax Pro
13 уровень , 4 лекция
Открыта

1. История LinkedList

В Java есть еще один класс-коллекция, который достался Java в наследство от языка C++. Это класс LinkedList, что переводится как «Связный Список».

Внешне LinkedList — это такой же список, как и ArrayList. У класса LinkedList есть все те же методы, что и у класса ArrayList. И в принципе вы всегда можете использовать LinkedList вместо ArrayList, и все будет работать.

Так зачем же нужен еще один класс-список?

Все дело во внутреннем устройстве класса LinkedList. Вместо массива там используется двусвязный список. Что это такое, расскажем немного позже.

Но за счет другого внутреннего устройства у класса LinkedList — самая быстрая операция вставки элементов в середину списка.

В интернете часто можно найти такое сравнение классов ArrayList и LinkedList:

Операция Метод ArrayList LinkedList
Добавление элемента
add(value)
Быстро Очень быстро
Вставка элемента
add(index, value)
Медленно Очень быстро
Получение элемента
get(index)
Очень быстро Медленно
Изменение элемента
set(index, value)
Очень быстро Медленно
Удаление элемента
remove(index)
Медленно Очень быстро

Вроде бы все понятно: если нужно вставлять элементы в список часто, используйте LinkedList, если редко, то ArrayList. Однако реальность немного другая.


2. Никто не использует LinkedList

Никто не использует LinkedList.

Недавно даже сам автор кода класса LinkedList в твиттере написал пост: «Ребята, кто-нибудь вообще использует LinkedList? За 20 лет я не использовал его ни разу!».

Так в чем же дело?

Во-первых, класс ArrayList стал вставлять элементы в середину списка очень быстро. При добавлении элемента в середину списка нужно сдвинуть все элементы после нужного на 1 в сторону конца списка. Раньше это занимало время.

Но сейчас все поменялось. Все элементы массива находятся рядом в одном блоке памяти, поэтому операция по сдвигу элементов массива выполняется очень быстрой низкоуровневой командой System.arraycopy().

К тому же, сейчас у процессоров большой кэш, и обычно весь массив попадает в такой кэш, поэтому элементы массива сдвигаются даже не в памяти, а в кэше процессора. Миллион элементов легко сдвигается за одну миллисекунду.

Во-вторых, класс LinkedList быстро вставляет элементы, если вы вставляете их с помощью итератора. Если вы с помощью итератора проходитесь по списку LinkedList и постоянно вставляете новые элементы (или удаляете существующие), это действительно супербыстрая операция.

Если же вы просто в цикле добавляете элементы внутрь класса LinkedList, к каждой быстрой операции вставки добавляется медленная операция «получение элемента».

Реальность гораздо ближе к такой ситуации:

Операция Метод ArrayList LinkedList
Добавление элемента
add(value)
Быстро Очень быстро
Вставка элемента
add(index, value)
Медленно Очень медленно
Получение элемента
get(index)
Очень быстро Очень медленно
Изменение элемента
set(index, value)
Очень быстро Очень медленно
Удаление элемента
remove(index)
Медленно Очень медленно
Вставка через итератор
it.add(value)
Медленно Очень быстро
Удаление через итератор
it.remove()
Медленно Очень быстро

Почему же операция получения элемента в LinkedList такая медленная?

Ответ на этот вопрос вы узнаете, если немного ознакомитесь с устройством LinkedList


3. Устройство LinkedList

LinkedList имеет альтернативное внутреннее устройство, если сравнивать его с ArrayList. Массива для хранения элементов у него внутри нет. Вместо этого он использует структуру данных под названием двусвязный список.

Каждый элемент двусвязного списка хранит ссылки на предыдущий и следующий элемент. Это чем-то напоминает очередь, где каждый человек запоминает того, кто стоит перед ним, и того, кто стоит после него.

Вот как выглядит такой список в памяти:

Устройство LinkedList

По бокам (серый фон) переменные first и last, которые хранят ссылки на объекты типа Node.

В середине вы видите цепочку объектов (именно объектов, не переменных) типа Node. Каждый из них состоит их трех полей:

  • prev — хранит ссылку на предыдущий объект типа Node (желтый фон).
  • value — хранит значение – элемент списка (зеленый фон).
  • next — хранит ссылку на следующий объект типа Node (синий фон)

Второй объект (адрес == F24) является следующим (next) для первого и предыдущим (prev) для третьего. Желтое поле третьего объекта содержит ссылку F24 и синее поле первого объекта содержит ссылку F24.

Стрелки с первого и третьего объектов указывают на один и тот же второй объект. Поэтому более правильно было бы нарисовать стрелки так.

Устройство LinkedList 1



4. Вставка элемента в связный список

Чтобы добавить человека в такую очередь, нужно просто согласие двух соседних людей. Первый из них запоминает новичка как нового: «этот человек за мной», а второй — как нового «этот человек передо мной».

Всего-то и нужно изменить ссылки двух соседних объектов:

Вставка элемента в связный список

Мы добавили в наш список новый элемент и поменяли ссылки второго и третьего объектов. Теперь новичок, следующий за вторым и предыдущий для третьего. Ну и у самого объекта-новичка нужно прописать правильные ссылки: предыдущий объект — второй, следующий объект — третий.

Удаление еще проще. Если мы хотим удалить, допустим 100-й объект из списка, нужно просто у 99-го объекта поменять next, чтобы он указывал на 101-й объект, а у 101-го объекта поменять prev, чтобы он указывал на 99. И все.

Вот только получить 100-й объект не так просто.


5. Получение элемента списка

Чтобы получить 100-й элемент связного списка, нужно:

Получить 1-й объект: на него ссылается переменная first у объекта LinkedList. У 1-го объекта есть ссылка (поле next) на 2-й объект. С ее помощью получаем второй объект. У 2-го объекта есть ссылка на третий, и т.д.

Если нам нужно получить ссылку на 100-й объект, нам нужно последовательно пройтись по всем объектам с 1-го до 100-го. А если нам нужен миллионный элемент списка, нужно последовательно перебрать миллион объектов!

А ведь если эти объекты добавлялись в список в разное время, они находятся в разных частях памяти и вряд ли одновременно попадают в кэш процессора. А это значит, что последовательный перебор элементов связного списка — вещь не просто медленная, а очень медленная.

Такие дела.

Так зачем мы тут учим, как устроен этот медленный LinkedList?

Все дело в том, что на собеседовании вас обязательно спросят, чем LinkedList отличается от ArrayList. Обязательно.


Комментарии (610)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Kairat Уровень 16
5 июля 2026
Это история о том как я жаловался на легкость изи задач и как жестко обосрался с хардами с этой лекций! Бывает!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Vatrysuku Уровень 21
20 мая 2026
В этой статье более подробно описана работа LinkedList тык
Blake555 Уровень 32
23 апреля 2026
Java Speak Уровень 1
28 февраля 2026
Пхаха))) "самая быстрая вставка в середину"... Тот кто писал лекцию вообще не понимает устройство LinkedList и вводит в заблуждение начинающих. Данная лекция - однозначно приносит только вред.
Grigoryvvv Уровень 17 Expert
21 февраля 2026
21.02.2026 / 14 уровень
Vladimir Уровень 23
16 февраля 2026
Задания составлены плохо и в конечном счете только вредят. Они формируют у обучающихся неверное представление об устройстве полей first и last связанного списка, т.к. исходят из того, будто бы first и last изначально инициализируются объектами типа Node (в реальности поля списка first и last не инициализируются ничем, null). Умные люди неслучайно придумали говорящие названия полей first и last. Ссылки на первый и последний элемент списка хранятся именно в них. А first.next и last.prev - это обращение ко второму и предпоследнему элементам связанного списка. И зачем только нужно было специально оговаривать, что: В середине вы видите цепочку объектов (именно объектов, не переменных) типа Node если по итогу вы решили сделать объектами не только середину, но и начало, и конец?
Timur Salakhov Уровень 21
11 февраля 2026
Рекомендую сначала попытаться написать односвязаный список, как получится Сначала очень просто, где есть Node first; А внутри ноды всего 2 поля String value, Node next. Здесь нужно привыкнуть и научиться спускаться "в глубину". А потом уже оптимизировать
Rei Уровень 32
27 января 2026
Только после обучения джаве на других ресурсах плюс с помощью гпт мне становится понятно содержимое лекций джавараш
Timur Salakhov Уровень 21
11 февраля 2026
на работе будет также
C0N5P1RACY Уровень 1
21 декабря 2025
сначала «таблицы скоростей», потом «никто не использует», потом «учите потому что спросят». 👉 LinkedList — это не «бесполезный класс», а специализированный инструмент 👉 В 90–95% обычного кода реально используют ArrayList 👉 LinkedList нужен в очень конкретных сценариях 👉 Учить его важно, чтобы понимать, КОГДА его НЕ надо использовать LinkedList НЕ умеет: «дай 100-й элемент сразу» Он делает: first → 1 next → 2 next → 3 … next → 100 ❗ каждый get(index) = пройтись с начала (или конца) ❗ O(n)
Probably not playing Уровень 28
23 января 2026
Благодарю за ваши развернутые комментарии по лекциям, очень помогает, плюсики вам накидываю🤝
Underdante Уровень 46
8 апреля 2026
создатель linkedList признался что ни разу его не использовал
Another Уровень 19
21 декабря 2025
Несколько сбивает с толку, что на диаграммах лекции показано, что первое и последнее звенья с заполненными полями-значениями связного списка не ссылаются на звенья first и last соответственно с незаполненными полями-значениями, то есть их соответствующие поля prev и next имеют значения null. Однако в правильном решении первой задачи и исходном коде второй задачи видно, что это не так, то есть их поля prev и next хранят ссылки на звенья first и last соответственно.