1. Переменные-ссылки

В языке Java переменные могут быть двух видов: переменные примитивного типа и все остальные. Вот про «все остальные» мы сейчас и поговорим.

На самом деле правильнее будет сказать, что есть переменные примитивного типа (primitive type variables) и ссылочные переменные (reference variables). Так что же это такое, эти ссылочные переменные?

В отличие от примитивных типов, которые позволяют хранить значения прямо внутри переменных, переменные ссылочных типов хранят ссылки на объекты. Т.е. где-то в памяти существует некий объект, а в переменной-ссылке просто хранится адрес этого объекта в памяти (ссылка).

Значения прямо внутри переменных хранят только примитивные типы, все остальные типы хранят только ссылку на объект. Ранее вы уже, кстати, сталкивались с двумя такими типами переменных — это переменные типа String и переменные типа массив.

И массив, и строка являются объектами, которые хранятся где-то в памяти. Переменные типа String и переменные типа массив хранят только ссылки на объекты.

Переменные int a, int b и double d — примитивные и хранят значение внутри себя.

Переменная String str — ссылочная и хранит адрес (ссылку) объекта типа String в памяти.

При присваивании примитивного значения переменной примитивного типа, его значение копируется (дублируется). При присваивании же ссылочной переменной копируется только адрес объекта, сам же объект при этом не копируется.


2. Суть ссылок

В чем принципиальное отличие переменных-ссылок от примитивных переменных?

Примитивная переменная — как коробка: в ней можно хранить какое-нибудь значение. Переменная-ссылка больше похожа на листок бумаги с телефонным номером на нем.

Машина vs ключи от машины

Представьте, что вы решили подарить другу на день рождения машину. Вы же не будете заворачивать ее в коробку и нести с собой: машина для этого слишком большая.

Гораздо удобнее взять с собой только ключи от машины и коробку, достаточно вместительную для них. А ваш друг и так все поймет, когда достанет из коробки ключи. Нет нужды нести с собой всю машину, когда можно просто передать ключи.

Человек vs его телефонный номер

Или еще один вариант: человек и его телефонный номер. Телефонный номер — не сам человек, но номер телефона можно использовать, чтобы звонить ему, спрашивать у него какую-то информацию, давать команды.

Ссылка тоже используется для взаимодействия с объектом. Все объекты взаимодействуют друг с другом при помощи ссылок. Вместо того, чтобы «обмениваться людьми», достаточно обменяться телефонными номерами.

При присваивании значения в примитивную переменную, его значение копируется (дублируется). При присваивании же значения ссылочной переменной копируется только адрес объекта («телефонный номер»), сам же объект при этом не копируется.

Ссылка даёт ещё одно преимущество: можно передать ссылку на объект в какой-нибудь метод, и этот метод будет в состоянии модифицировать (изменять) наш объект, используя ссылку на него, вызывая его методы и обращаясь к данным внутри объекта.


3. Присваивание ссылок

При присваивании ссылочных переменных происходит просто присваивание адреса объекта в памяти. Сами объекты при этом не появляются и не исчезают.

Такой подход позволяет избежать копирования больших объемов памяти. Если куда-то нужно передать очень большой объект, мы просто передадим в этот метод ссылку на объект и все. Ссылка занимает гораздо меньше места.

Присваивание ссылок

Размер всех переменных-ссылок (независимо от типа) одинаков и составляет 4 байта (как тип int). Но! Если ваше приложение запущено на 64-х разрядной Java-машине, размер всех ссылок будет 8 байт (64 бита).

Ссылки при этом можно только присваивать друг другу. Вы не можете менять ссылки или присваивать им произвольные значения:

Код Описание
String hello = "Привет";
String s = hello;
Так можно
String hello = "Привет";
hello++;
А так — нельзя
String hello = 0x1234;
И так — нельзя

4. Пустая ссылка — null

А что хранит переменная-ссылка, если ей еще ничего не присвоили?

А хранит она пустую ссылку — null. null — это специальное ключевое слово в Java, обозначающее отсутствие ссылки (пустую ссылку). Значение null можно присвоить любой ссылочной переменной.

Все переменные-ссылки, если им не присвоена какая-нибудь ссылка, имеют значение null.

Примеры:

Код Описание
class Person
{
   public static String name;
   public static int age;
}


Переменная String name имеет значение по умолчанию: null.
Переменная int age имеет значение по умолчанию: 0.

Локальные переменные без значения считаются неинициализированными как для примитивных типов, так и для типов-ссылок.

Если переменная хранит ссылку на какой-то объект, а вы хотите стереть значение переменной, просто присвойте ей ссылку null.

Код Описание
String s = null;
s = "Привет";
s = null;
s хранит ссылку null.
s хранит ссылку на объект-строку
s хранит ссылку null

5. Передача ссылок в методы

Если у какого-нибудь метода есть параметры ссылочные переменные, передача значений в них происходит точно так же, как и при работе с обычными переменными. Переменной-параметру просто присваивается значение другой переменной.

Пример:

Код Описание
class Solution
{
   public static void fill(String[] array, String value)
   {
      for (int i = 0; i < array.length; i++)
        array[i] = value;
   }

   public static void main(String[] args)
   {
     String[] data = new String[10];
     fill(data, "Hello");
   }
}


Метод fill заполняет переданный массив array переданным значением value.

При вызове метода fill переменной array присваивается ссылка на массив data. Переменной value присваивается ссылка на объект-строку «Hello».

Вот как будет выглядеть ситуация в памяти перед вызовом метода fill:

Передача ссылок в методы

Вот как будет выглядеть ситуация во время работы метода fill:

Передача ссылок в методы 2

Переменные data и array ссылаются (хранят ссылки) на один и тот же массив-контейнер в памяти.

Переменная value хранит ссылку объекта строки Hello.

Ячейки массива тоже хранят просто ссылки на объект Hello.

Фактически никакого дублирования объектов не происходит — копируются только ссылки.


6
Задача
Модуль 1. Java Syntax,  12 уровень1 лекция
Недоступна
Создадим небоскреб
Попробуем сконструировать свой первый небоскреб и объявить о результате выполнения в консоли. Для этого тебе нужно вызвать конструктор класса Skyscraper в методе main и в теле конструктора вывести в консоль текст "Небоскреб построен.".
6
Задача
Модуль 1. Java Syntax,  12 уровень1 лекция
Недоступна
Построим новый жилой комплекс JavaRush Towers
Давай построим жилой комплекс из трех высоток. Для этого мы будем использовать три разных способа вывода информации: 1. Объявляет о результате постройки. 2. Объявляет о результате и указывает количество этажей. 3. Объявляет о результате и указывает застройщика. Пример вывода: Небоскреб построен

6. Сравнение с языком С/С++

Иногда Java-программистов спрашивают на собеседовании: как передаются данные в методы в Java? Иногда еще уточняют: по ссылке или по значению?

Этот вопрос идет из языка С++ — в языке Java он не имеет смысла. В Java переменным-параметрам всегда просто присваиваются значения переменных-аргументов. Так что правильным ответом будет — по значению.

Но будьте готовы к тому, чтобы объяснить свою позицию, т.к. вам могут тут же возразить, что «примитивные типы передаются по значению, а ссылочные – по ссылке».

Истоки этой проблемы связаны с тем, что многие Java-программисты были в прошлом С++ программистами. А там вопрос «как передаются параметры в методы» играл очень важную роль.

В Java все однозначно: примитивные типы хранят значения, ссылочные тоже хранят значение — ссылку. Все дело в том, что считать значением переменной.

В языке C++ в переменной можно было хранить как ссылку на объект, так и сам объект. То же касалось примитивных типов: в переменной можно было хранить значение или объявить переменную ссылкой на тип int. Поэтому чтобы не путаться, С++ программисты ссылку на объект всегда называют ссылкой, а сам объект — значением.

В С++ легко могла сложиться ситуация, что одна переменная содержит объект, а другая — ссылку на этот же объект. Поэтому вопрос, что хранит в себе переменная — сам объект или только ссылку на него — был очень важен. При передаче в метод объекта он копировался (если передавался по значению), и не копировался (если передавался по ссылке).

В Java этой двойственности нет, и правильный ответ звучит так: параметры в методы Java передаются по значению. Просто в случае с ссылочными переменными это значение — ссылка.