JavaRush/Java блог/Java Developer/Ссылочные типы данных в Java
Автор
Александр Выпирайленко
Java-разработчик в Toshiba Global Commerce Solutions

Ссылочные типы данных в Java

Статья из группы Java Developer
участников
Без понимания синтаксиса 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 привязаны лишь к одному объекту без возможности переопределения.
Комментарии (16)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
MrFurion
Уровень 32
3 апреля 2023, 18:58
,Что за бред. Сначало вы говорите строка это ссылочный тип, потом говорите примитивный так как она состоит из символов, потом говорите это ссылочный потому что это класс. Так какой он тип может кто-то объяснить нормально?
YesOn
Уровень 13
1 августа 2021, 13:21
Не понял про неизменяемость класса String: String text = "This TV"; text = text + " is very loud"; Вторая строка написана ошибочно и компилятор её не пропустит? Потому что переменная text так и останется со значением = "This TV"; ? Или что имелось ввиду?
YesOn
Уровень 13
1 августа 2021, 14:10
Посмотрел информацию в разных источниках и понял, что в этой статье объяснение самое простое, но правда поверхностное. Похоже это вопрос достаточно глубокий и понимание придёт позже, когда подтянутся другие составляющие этого пазла.
wwhysohard Backend Developer
9 сентября 2021, 09:14
Кусок text + "is very loud" создаёт новый объект класса String, затем ссылка text присваивается к этому новому объекту.
Viktor
Уровень 1
26 октября 2022, 16:34
Мы переопределяем наш "text"
YesOn
Уровень 13
27 октября 2022, 07:26
Теперь уже мне неизменяемость класса String пронятно. wwhysohard дал исчерпывающий ответ, спасибо)
gunsroses
Уровень 22
14 сентября 2020, 09:48
TV telly = new TV(); Переменной типа TV с именем telly мы задаем ссылку на создаваемый объект типа TV. скажите пожалуйста, тип переменной и объекта TV должны быть одинаковыми это понятно, а где сам объект ??? )
Toro Rosso
Уровень 17
2 октября 2020, 17:00
в памяти
Roman Doroshenko
Уровень 16
1 февраля 2021, 06:33
Объект создается и хранится в памяти, в куче. А пульт управления этим объектом - telly , переменная ссылочного типа.
Darth Nihilus Разработчик спокойствия в Rage&Flame Industrie
8 апреля 2021, 22:00
new выделяет память под объект + создает его, возвращает ссылку
Иван Серов
Уровень 7
14 апреля 2020, 07:12
Спасибо за статью, гораздо понятней чем лекция в курсе, но все же кой что до конца так и не понял а именно назначение вот этой строки: final TV telly = new TV(); Для чего она , и если написать вот так : public class TV { int numberOfChannel; int soundVolume; boolean isOn; public void enableTV (){ int x= TV.numberOfChannel; } }
Константин Backend Developer в Andersen
18 апреля 2020, 16:17
Вопрос непонятен TV.numberOfChannel - обращение к статической переменной, которой у вас таковой не является(компилятор не одобрит, не простит) final TV telly = new TV(); - привязывает ссылку telly к конкретному, одному объекту TV без возможности переопределения
Viktor
Уровень 1
26 октября 2022, 16:36
При final TV telly = new TV() telly = null; telly = new TV(); не сработают
Demitelix
Уровень 11
11 апреля 2020, 01:13
Спасибо
sergey
Уровень 22
10 апреля 2020, 15:48
статья по мотивам Head First Java?
Anna
Уровень 0
30 августа 2020, 13:34
Очень похожа