JavaRush /Курси /Java Syntax Zero /Нюанси об'єктів у Java

Нюанси об'єктів у Java

Java Syntax Zero
Рівень 11 , Лекція 4
Відкрита

1. Властивості: геттер і сетер

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

Ніхто детально не вивчає документацію по класах, або в ній можуть бути не описані всі випадки, тому часто можуть виникати ситуації, коли дані всередині об'єкта «псуються», і об'єкт стає невалідним.

Щоб уникнути таких ситуацій, у Java прийнято всі поля класу робити private. Тільки методи класу можуть змінювати змінні класу, і жодні методи з інших класів не мають доступу до змінних класу напряму. Ось так.

Якщо ви хочете, щоб інші класи могли отримувати або змінювати дані всередині об'єктів вашого класу, ви повинні додати в код вашого класу два методи — get-метод і set-метод. Приклад:

Код Примітка
class Person
{
   private String name;

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

   public String getName()
   {
      return name;
   }

   public void setName(String name)
   {
      this.name = name;
   }
}


private-поле name



Ініціалізація поля через конструктор


getName()— метод повертає значення поля name




setName()— метод змінює значення поля name

Жоден інший клас не зможе змінити значення поля name напряму. Якщо комусь потрібно отримати значення поля name, йому доведеться викликати метод getName() у об'єкта типу Person. Якщо якийсь код хоче змінити значення поля name, йому потрібно буде викликати метод setName() у об'єкта типу Person.

Метод getName() ще називають «геттер поля name», а  метод setName() — «сетер поля name».

Це дуже поширений підхід. У 80-90% всього Java коду ви ніколи не побачите публічні змінні класу. Замість цього вони будуть оголошені private (або protected), і у кожної змінної будуть публічні геттери та сеттери.

Цей підхід робить код довшим, але надійнішим.

Звертання до змінної класу напряму — це як поворот через подвійну суцільну: простіше і швидше, але якщо так будуть робити всі, то всім же буде від цього і гірше.

Припустимо, ви хочете створити клас, що описує точку на площині x і y. Ось як це зробив би програміст-початківець:

class Point
{
   public int x;
   public int y;
}

А ось як це зробив би досвідчений Java-програміст:

Код
class Point {
 private int x;
 private int y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y;
   }
}

Код став довшим? Безсумнівно.

Зате в сетери та геттери можна додати валідацію параметрів. Наприклад, можна слідкувати за тим, щоб x і y завжди були більше нуля (або не менше нуля). Приклад:

Код Примітка
class Point {
   private int x;
   private int y;

   public Point(int x, int y) {
      this.x = x < 0 ? 0 : x;
      this.y = y < 0 ? 0 : y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x < 0 ?  0 : x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y < 0 ? 0 : y;
   }
}


2. Час життя об'єкта

Ви вже знаєте, що об'єкти створюються за допомогою оператора new, а ось як об'єкти видаляються? Не існують же вони вічно — для цього жодної пам'яті не вистачить.

У багатьох мовах програмування, таких як С++, для видалення об'єкта є спеціальний оператор delete. А як ситуація з цим в Java?

У Java все влаштовано трохи інакше, і оператора delete в Java немає. Чи означає це, що об'єкти в Java не видаляються? Ні, видаляються звісно ж. Інакше в Java-додатках швидко закінчилася б пам'ять, і ні про які місяці безперервної роботи не йшло б і мови.

У Java процес видалення об'єктів повністю автоматизований – видаленням об'єктів займається сама Java-машина. Такий процес називається збиранням сміття (garbage collecting), а механізм, що збирає сміття — збирачем сміттяGarbage Collector, або скорочено GC.

Як Java-машина дізнається, що якийсь об'єкт потрібно видалити і коли?

Усі об'єкти збирач сміття ділить на досяжні та недосяжні. Якщо на об'єкт є хоча б одне посилання, він вважається досяжним. Якщо немає жодної змінної, яка посилається на об'єкт, такий об'єкт вважається недосяжним і оголошується сміттям: значить, його можна видаляти.

У Java не можна взяти й створити посилання на існуючий об'єкт: її можна лише призначити. Якщо ми стерли всі посилання на об'єкт, він втрачений назавжди.

Циклічні посилання

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

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

Саме тому збирач сміття ділить об'єкти не на «об'єкти з посиланнями» і «об'єкти без посилань», а на досяжні та недосяжні.

Досяжні об'єкти

Спочатку у список досяжних додаються ті об'єкти, які 100% живі. Наприклад, поточний потік (Thread.current()) або Консоль (System.in).

Потім список досяжних об'єктів поповнюють ті, на які посилаються перші досяжні об'єкти. Потім ті, на кого посилаються другі, і т.д.

Таким чином, якщо є якась група об'єктів, які посилаються тільки один на одного, але від досяжних об'єктів до них ніяк дістатися не можна, такі об'єкти будуть вважатися сміттям і будуть видалені.


3. Збирання сміття

Фрагментація пам'яті

Ще один важливий момент, пов'язаний із видаленням об'єктів — фрагментація пам'яті. Якщо постійно створювати та видаляти об'єкти, скоро вся пам'ять буде впереміш: області зайнятої пам'яті будуть постійно перемежовуватись пустими областями.

І легко може трапитися ситуація, коли ми не можемо створити великий об'єкт (наприклад, масив на мільйон елементів), тому що немає великого куска вільної пам'яті. Тобто вільна пам'ять начебто і є, і багато, але от великого цільного куска вільної пам'яті може і не бути.

Оптимізація (дефрагментація) пам'яті

Java-машина вирішує цю проблему специфічним чином. Виглядає це приблизно так:

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

Виглядає цей процес приблизно так:

Етап 1: Після створення об'єктів

Сборка сміття в Java

Етап 2: Поява «дір»

Сборка сміття в Java

Етап 3: Усунення «дір»

Сборка сміття в Java

Таким чином, навіть не потрібно видаляти об'єкти. Java-машина просто копіює всі досяжні об'єкти в нове місце, а всю область пам'яті зі старими об'єктами оголошує вільною.

Коментарі (14)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
24 лютого 2024
Могли бы преподователи написать, что в getName() и setName() "Name" - это назание переменной, но только с большой буквы ?! Как это потом используется в задачах. В лекции это неочевидно написано, а я тыкал повсюду именно такое написание методов, а мне все "неправильно!!!" в ответ. Пишите, что getName(), где Name - это назание переменной с большой буквы в сносках и ВСЁ!!! Может это и не так я понял, но в задачах именно такая логика.
Ва Дим Рівень 28
2 квітня 2024
але там же приклажи є.Якщо перший не дає відповіді то в прикладі з х і у вже видно
2 квітня 2024
Здогадуватись та знати (з лекції) - різні слова.
Василь Рівень 4
27 серпня 2023
там де треба прописати гетер або сетер, то в Intelliage IDEA можна натиснути Alt + Insert і вибрати вставку гетера, сетера або обидва для потрібних полів.
Олег Рівень 111 Expert
16 квітня 2023
Щось до цієї лекції мало коментарів) Мабуть це той рівень на якому вирішують продовжувати навчання. Не все так складно)
Valentyna Рівень 30
11 січня 2024
Теж на це звернула увагу. Ви, бачу, все ж продовжили навчання.
Олег Рівень 111 Expert
16 січня 2024
Так з великими тормозами але продовжую ) Все ж хочу опанувати цю справу.
Денис Бурдужан Рівень 111
30 червня 2024
і як воно? Ще продовжуєте?
Олег Рівень 111 Expert
20 липня 2024
Продовжую! Мало що розумію але продовжую )))
Vlad Рівень 21
26 вересня 2024
111 рівень, машина 💪 До якого я дійду, цікаво...
kalkulator¹ Рівень 51
7 листопада 2022
/* Comment has been deleted */
Beisik Рівень 25
9 листопада 2022
Ну так в умові так написано)
Roma Chernesh Рівень 16
7 січня 2023
у якій задачі?
Lipovskyi Volodymyr Рівень 36
16 травня 2022
Так вон для чого потрібна дефрагментація)))