JavaRush /Java блог /Random UA /Посилальні типи даних у Java

Посилальні типи даних у Java

Стаття з групи Random UA
Без розуміння синтаксису Java неможливо стати серйозним розробником, тому ми продовжуємо вивчати синтаксис. В одній із минулих статей ми говорабо про примітивні змінні, але так як видів змінних два, сьогодні ми поговоримо про другий вид — типи посилань у Java. То що це? Навіщо потрібні типи даних у Java? Посилальні типи даних у Java - 1Давайте уявимо, що у нас є об'єкт телевізор з деякими характеристиками, такими як номер каналу, гучність звуку та прапор увімкненості:
public class TV {
   int numberOfChannel;
   int soundVolume;
   boolean isOn;
}
Як простий тип, наприклад, intможе зберігати ці дані? Нагадаємо: одна змінна int- це 4 байти. Адже там усередині є дві змінні (4 байти + 4 байти) цього ж типу, та ще й boolean(+1 байт)... Разом — 4 до 9, адже як правило, в об'єкті зберігається набагато більше інформації. Що робити? Не можна ж вкласти об'єкт у змінну. На цьому моменті в нашій історії з'являються перемінні посилання. Посилальні змінні зберігають адресау осередку пам'яті, в якій розташований певний об'єкт. Тобто це візитка з адресаою, маючи яку ми можемо знайти наш об'єкт у загальній пам'яті і виконувати з ним деякі маніпуляції. Посилання на будь-який об'єкт у Java є посилальною змінною. Як би це виглядало з нашим об'єктом телевізора:
TV telly = new TV();
Змінної типу TV з ім'ям tellyми задаємо посилання на об'єкт типу TV, що створюється. Тобто, JVM виділяє пам'ять у купі під об'єкт TV, створює його та адресау на його місце розташування в пам'яті, кладеться в змінну, tellyяка зберігається в стеку. Детальніше про пам'ять, а саме про стек і ще масу корисного, можна почитати в цій лекції. Змінна типу TV та об'єкт типу TV, помітабо? Це неспроста: об'єктам певного типу повинні відповідати змінні такого самого типу (крім успадкування та реалізацій інтерфейсів, але зараз ми це не враховуємо). Зрештою, не будемо ж ми в склянки наливати суп? Виходить, що у нас об'єкт — це телевізор, а посилальна змінна для нього — ніби пульт керування. За допомогою цього пульта ми можемо взаємодіяти з нашим об'єктом та його даними. Наприклад, задати характеристики для нашого телевізора:
telly.isOn = true;
telly.numberOfChannel = 53;
telly.soundVolume = 20;
Тут ми використовували оператор точки .— щоб отримати доступ і розпочати використання внутрішніх елементів об'єкта, на який посилається змінна. Наприклад, у першому рядку ми сказали змінній telly: “Дай нам внутрішню змінну isOnоб'єкта, на який ти посилаєшся, і задай їй значення true” (включи телевізор).

Перевизначення посилальних змінних

Припустимо, у нас є дві змінні типу посилання та об'єкти, на які вони посилаються:
TV firstTV = new TV();
TV secondTV = new TV();
Якщо ми напишемо:
firstTV = secondTV;
це означатиме, що ми першою змінною як значення привласнабо копію адресаи (значення бітів адресаи) на другий об'єкт, і тепер обидві змінні посилаються на другий об'єкт (інакше кажучи, два пульти від одного й того самого телевізора). У той же час перший об'єкт залишився без змінної, яка на нього посилається. У результаті у нас є об'єкт, до якого неможливо звернутися, адже змінна була такою умовною ниточкою до нього, без якої він перетворюється на сміття, просто лежить у пам'яті та посідає місце. Згодом цей об'єкт буде знищений із пам'яті збирачем сміття . Посилальні типи даних у Java - 2Перервати сполучну ниточку з об'єктом можна і без іншого посилання:
secondTV = null;
У результаті посилання на об'єкт залишиться одне - firstTV, а secondTVвже ні на кого вказувати не буде (що не заважає нам надалі привласнити посилання на який-небудь об'єкт типу TV).

Клас String

Окремо хотілося б згадати клас String . Це базовий клас, призначений для зберігання та роботи з даними, що зберігаються у вигляді рядка. Приклад:
String text = new String("This TV is very loud");
Тут ми передали рядок для зберігання у конструкторі об'єкта. Але ж ніхто так не робить. Адже рядки можна створювати:
String text = "This TV is very loud";
Набагато зручніше, правда? За популярністю використання Stringне поступається примітивним типам, але все ж таки це клас, і змінна, яка посилається на нього - не примітивного, а посилання типу. Є Stringтака чудова можливість конкатенації рядків:
String text = "This TV" + " is very loud";
У результаті ми знову отримаємо текст: This TV is very loud, тому що два рядки з'єднаються в одне ціле, і змінна посилатиметься на цей текст. Важливим нюансом є те, що Stringце незмінний клас. Що це означає? Візьмемо такий приклад:
String text = "This TV";
text = text + " is very loud";
Начебто все просто: оголошуємо змінну, задаємо їй значення. На наступному рядку змінюємо його. Але не зовсім і змінюємо. Так як це незмінний клас, на другому рядку початкове значення не змінюється, а створюється нове, яке, у свою чергу, складається з першого + " is very loud".

Посилальні константи

У статті про примітивні типи ми торкалися теми констант. Як же поводитиметься посилальна змінна, коли ми оголосимо її final ?
final TV telly = new TV();
Можливо, ви подумаєте, що це зробить об'єкт незмінним. Але ж ні, це не так. Посилальні типи даних Java - 3Посилальна змінна з модифікатором finalбуде прив'язана до певного об'єкта без можливості її відв'язати (перевизначити або прирівняти до null). Тобто після завдання значення такої змінної код виду:
telly = new TV();
або
telly = null;
буде викликати помилку компіляції. Тобто finalдіє лише на заслання, а на сам об'єкт впливу не робить. Якщо спочатку він у нас змінюється, ми без проблем можемо змінювати його внутрішній стан:
telly.soundVolume = 30;
Іноді змінні позначають як final навіть у аргументах методу!
public void enableTV (final TV telly){
   telly.isOn = true;
}
Це робиться для того, щоб у процесі написання методу ці аргументи не можна було перевизначити і створити менше плутанини. А якщо позначити finalпосилальну змінну, яка посилається на незмінний об'єкт? Наприклад String:
final String PASSWORD = "password";
Як наслідок ми отримаємо константу, аналог констант примітивного типу, адже тут ми не можемо ні перевизначити посилання, ні змінити внутрішній стан об'єкта (внутрішні дані).

Підведемо підсумки

  1. Якщо прості змінні зберігають біти значень, посилальні змінні зберігають біти, що представляють спосіб отримання об'єкта.
  2. Посилання на об'єкти оголошуються лише одного виду об'єктів.
  3. Будь-який клас в Java - це тип посилання.
  4. За замовчуванням Java значення будь-якого змінного посилання — null.
  5. String- Стандартний приклад посилального типу. Також цей клас є незмінним (immutable).
  6. Посилальні змінні з модифікатором finalприв'язані лише одного об'єкту без можливості перевизначення.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ