Вітання! У попередніх лекціях ми детально розібрали таку структуру даних як масив і розглянули найпоширеніші приклади роботи з ними. Але ця структура даних має низку недоліків. Відповіддю на них у Java стала поява ArrayList. Якщо говорити максимально просто, то список ArrayList в Java - це "прокачаний" масив з великою кількістю нових можливостей.Клас ArrayList - 1

Чим Java Arraylist відрізняється від звичайних масивів?

Взагалі, масиви - штука досить зручна і як ти вже помітив, з ними можна багато чого робити :) Тим не менш, масиви мають і ряд недоліків.
  • Обмежений розмір. Потрібно вже на етапі створення масиву знати, скільки осередків він має містити. Недооціниш потрібну кількість — місця не вистачить. Переоціниш - масив залишиться напівпорожнім, і це ще півбіди. Адже виходить, ти ще й виділиш під нього більший обсяг пам'яті, ніж потрібно.
  • У масиву немає методів додавання елементів. Завжди доводиться явно вказувати індекс комірки, куди додати елемент. Якщо ненароком вказати вже зайняту комірку з якимось потрібним значенням, воно перезапишеться.
  • Немає методів видалення елемента. Значення можна лише "обнулити".
public class Cat {

   private String name;

   public Cat(String name) {
       this.name = name;
   }

   public static void main(String[] args) {

       Cat[] cats = new Cat[3];
       cats[0] = new Cat("Томас");
       cats[1] = new Cat("Бегемот");
       cats[2] = new Cat("Філіп Маркович");

       cats[1] = null;



       System.out.println(Arrays.toString(cats));
   }

   @Override
   public String toString() {
       return "Cat{" +
               "name='" + name + '\'' +
               '}';
   }
}
Висновок:

[Cat{name='Томас'}, null, Cat{name='Фабопп Маркович'}]
Всі ці недоліки можна усунути, використовуючи ArrayList. Створюється він дуже просто:
ArrayList<Cat> cats = new ArrayList<Cat>();
Тепер ми створили список для зберігання об'єктів Cat. Зверни увагу:ми не вказуємо розмір ArrayList'a, оскільки він автоматично розширюється. Як таке можливо? Легко. Ти здивуєшся, але в основі ArrayList'a лежить звичайнісінький масив :) Так, всередині у нього знаходиться масив, в якому зберігаються наші елементи. Але у ArrayList'a є спеціальний механізм роботи з ним:
  • Коли цей внутрішній масив заповнюється, ArrayList створює в собі новий масив. Його розмір = (Розмір старого масиву * 1,5) +1.
  • Всі дані копіюються зі старого масиву в новий
  • Старий масив видаляється збирачем сміття.
Завдяки цьому механізму ArrayList'e (на відміну від масиву) реалізований метод для додавання нового елемента. Це метод add().
public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<Cat>();
   cats.add(new Cat("Бегемот"));
}
Новий елемент додається до кінця списку. Тепер ризику переповнення немає, тому такий механізм є повністю безпечним. До речі, ArrayList вміє не тільки шукати об'єкт за індексом, а й навпаки – може знайти індекс об'єкта в ArrayList'і за посиланням на об'єкт! Для цього в ньому реалізований метод indexOf(): Ми передаємо в нього посилання на потрібний об'єкт, і indexOf()повертає нам його індекс:
public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Томас");
   Cat behemoth = new Cat("Бегемот");
   Cat philipp = new Cat("Філіп Маркович");
   Cat pushok = new Cat("Пушок");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(philipp);
   cats.add(pushok);

   int thomasIndex = cats.indexOf(thomas);
   System.out.println(thomasIndex);
}
Висновок:

0
Все вірно, об'єкт thomasдійсно зберігається в комірці 0. У масивів є не лише недоліки, а й безперечні переваги. Один із них — пошук елемента за індексом. Оскільки ми вказуємо на індекс, тобто на конкретну адресау пам'яті, такий пошук у масиві здійснюється дуже швидко. ArrayList у Java теж так уміє! Для цього в ньому реалізовано метод get():
public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Томас");
   Cat behemoth = new Cat("Бегемот");
   Cat philipp = new Cat("Філіп Маркович");
   Cat pushok = new Cat("Пушок");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(philipp);
   cats.add(pushok);

   Cat secondCat = cats.get(1);

   System.out.println(secondCat);
}
Висновок:

Cat{name='Бегемот'}
Крім того, можна легко дізнатися, чи містить ArrayList якийсь конкретний об'єкт, чи ні. Це робиться за допомогою методу contains():
public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Томас");
   Cat behemoth = new Cat("Бегемот");
   Cat philipp = new Cat("Філіп Маркович");
   Cat pushok = new Cat("Пушок");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(philipp);
   cats.add(pushok);

   cats.remove(pushok);
   System.out.println(cats.contains(pushok));
}
Метод перевіряє, чи міститься елемент у внутрішньому масиві ArrayList'a, і повертає результат у вигляді boolean- trueабо false. Висновок:

false
І ще важливе з приводу вставки. ArrayList дозволяє вставляти дані не тільки в кінець масиву, але і в будь-яку комірку за індексом. Для цього він має два методи:
  • add(int index, Cat element)
  • set(int index, Cat element)
В обидва ти передаєш індекс осередку, в який потрібно зробити вставку, та посилання на сам об'єкт. Різниця в тому, що вставка через set()затирає старе значення, що зберігається в комірці. А вставка через add()спочатку зрушує всі елементи починаючи з [index]до кінця масиву, а в порожню комірку, що утворилася, додає потрібний тобі об'єкт. Ось приклад:
public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Томас");
   Cat behemoth = new Cat("Бегемот");
   Cat philipp = new Cat("Філіп Маркович");
   Cat pushok = new Cat("Пушок");

   cats.add(thomas);
   cats.add(behemoth);

   System.out.