— Якщо ти думаєш, що на інтерфейсі List все закінчилося, то помиляєшся, все тільки починається. Давай я тобі розповім про колекції LinkedList і ArrayList.

Почну з колекції ArrayList.

Ось як ця колекція виглядає на схемі успадкування:

Реалізації інтерфейсу List 1

Зеленим відзначені інтерфейси.

Фіолетовим – абстрактні класи.

Червоним – звичайні класи.

Суцільна лінія – успадкування, пунктирна – реалізація інтерфейсу.

Це найпростіша колекція. Всередині ArrayList зберігає елементи в простому масиві.

Основна перевага такої колекції над масивом – це розширюваність – збільшення довжини за потреби.

Якщо в цьому масиві закінчується місце, створюється другий масив побільше, куди копіюються всі елементи з першого. Потім другий масив займає місце першого, а перший викидається (буде знищений збирачем сміття).

— А наскільки збільшується масив?

— Довжина нового масиву розраховується так (3*n)/2+1 де n – це довжина старого масиву. Тобто. якщо старий масив був довжиною 100 елементів, новий буде 300/2+1 = 151.

При додаванні елемента в середину ArrayList, всі елементи праворуч від нього копіюються на 1 позицію вправо, а потім в порожню комірку додається новий елемент.

При видаленні елемента з середини всі елементи праворуч від нього копіюються на 1 позицію вліво.

— Ти кажеш, що ArrayList сам подовжується при додаванні елементів до нього. А при видаленні він сам коротшає?

— Ні, сам внутрішній масив у ArrayList ніколи не коротшає, але можна змусити ArrayList зменшити свій внутрішній масив до мінімального рівня, якщо викликати методtrimToSize().

Ну, і звичайно, розповім про LinkedList.

Ось як виглядає його схема успадкування:

Зеленим відзначені інтерфейси.

Фіолетовим – абстрактні класи.

Червоним – звичайні класи.

Суцільна лінія – успадкування, пунктирна – реалізація інтерфейсу.

Як ти вже знаєш, LinkedList зберігає елементи у вигляді зв'язкового списку.

— Я постійно чую про це, але не могла б ти розповісти, що це таке?

— Звичайно. Все просто.

Зв'язковий список складається з однакових елементів, які а)зберігають дані,б)зберігають посилання на наступний і попередній елементи.

От так виглядав би клас такого елемента для зберігання рядків:

Приклад Опис
class LinkedListElement
{
String data;
LinkedListElement next;
LinkedListElement previous;
}
data зберігає рядкове значення елемента.
next зберігає посилання на наступний елемент у списку.
previous зберігає посилання на попередній елемент у списку.

А якщо використовувати generics для типу даних, то буде щось такого типу:

Клас елемента зв'язкового списку з generic’ом
class LinkedListElement<T>
{
 T data;
LinkedListElement<T> next;
LinkedListElement<T> previous;
}

— Ясно.

— Давай, для кращого розуміння, напишемо код, де додамо до двозв'язкового списку 10 елементів:

Приклад
public static void main(String[] args)
{
 LinkedListElement<Integer> tail; // хвіст (останній елемент) списку

 for(int i=0;i<10;i++)
 {
 LinkedListElement<Integer> element = новий LinkedListElement<Integer>< /span>();
  element.data = i;

  if (tail == null) //якщо в хвості немає елементів, зробити наш елемент останнім
  {
   tail = element;
  }
  else //якщо хвіст є, додати елемент
  {
   tail.next = element; //додаємо хвосту посилання на наступний елемент
 element.previous = tail; //додаємо новому елементу посилання на хвіст
   tail = element; //оголошуємо новий елемент хвостом.
  }
 }
}

Допустимо у нас у списку 10 елементів, ось як вставити елемент у середину:

Реалізації інтерфейсу List - 3

Яскраво-червоним виділені посилання, які змінилися – вони тепер вказують на новий елемент.

Яскраво-фіолетовим Виділені нові посилання – посилання нового елемента на його сусідів.

А тепер – кодом:

Вставлення елемента до середини списку зв'язку
//тут міститься елемент – голова списку
LinkedListElement<Integer> head = …

//отримуємо 4-й елемент (нумерація з нуля)
LinkedListElement<Integer> element4 = head.next.next.next.next;
//отримуємо 5-й елемент
LinkedListElement<Integer> element5 = element4. next;

//Створюємо новий елемент, який вставлятимемо
LinkedListElement<Integer> newElement = new LinkedListElement<Integer>< /span>();
newElement.data = -18;

//обмінюємося посиланнями з елементом зліва
newElement.previous = element4;
element4.next = newElement;

//обмінюємося посиланнями з елементом праворуч
newElement.next = element5;
element5.previous = newElement;

— Дякую, Еллі, справді дізнався про списки багато нового.