JavaRush /Курсы /Java Syntax Pro /Сравнение ссылок

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

Java Syntax Pro
3 уровень , 5 лекция
Открыта

1. Сравнения

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

Целые числа сравнивать очень легко — просто используйте == и все. Чтобы сравнить вещественные числа, вам уже придется сравнивать их разность (вернее, модуль разности) с каким-нибудь очень маленьким числом.

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


2. Расположение строк в памяти

Как вы уже успели увидеть, строки в памяти хранятся не так, как целые и вещественные числа:

Расположение строк в памяти

Для хранения строк используется два блока памяти: один блок хранит сам текст (его размер зависит от размера текста), а второй (размером 4 байта) хранит адрес первого блока.

Хотя опытный программист в такой ситуации скажет что-то вроде «Переменная str типа String хранит ссылку на объект типа String».


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

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

String text = "Это очень важное сообщение";
String message = text;

А вот что в результате будет в памяти:

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

В результате этой операции присваивания объект String так и останется, где был, а в переменную message скопируется только его адрес (ссылка на объект).


4. Работа со ссылками и объектами

А вот если вы решите преобразовать строку к верхнему регистру (заглавные буквы), Java-машина сделает все правильно: у вас будут два объекта типа String, и переменные text и message будут хранить ссылки: каждая на свой объект.

Пример:

String text = "Это очень важное сообщение";
String message = text.toUpperCase(); 

А вот что в результате будет в памяти:

Работа с ссылками и объектами

Обращаю ваше внимание, что метод toUpperCase() не меняет ту строку, у которой он был вызван. Вместо этого он создает новую строку (новый объект) и возвращает ссылку на него.

Или еще более интересный пример. Скажем, вы решили передать строку в объект типа Scanner (чтобы он читал значения из нее).

Пример:

String text = "10 20 40 80";
Scanner console = new Scanner(text);
int a = console.nextInt();
int b = console.nextInt();

Подробнее о работе класса Scanner вы можете узнать по ссылке.

Вот как это все будет храниться в памяти:

Работа с ссылками и объектами. Scanner

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


5. Сравнение ссылок на объекты типа String

Ну и наконец мы дошли до самого интересного — сравнения строк.

Для сравнения строковых переменных можно использовать два оператора: == (равно) и != (не равно). Операторы «больше», «меньше», «больше либо равно» использовать нельзя — компилятор не допустит.

Но есть интересный нюанс: что у нас хранится в строковых переменных? Правильно: адреса (ссылки) на объекты. Вот эти самые адреса сравниваться и будут:

String text = "Привет";
String message = text;
String s1 = text.toUpperCase();
String s2 = text.toUpperCase(); 

Вот что будет в памяти:

Сравнение ссылок на объекты типа String

Переменные message и text хранят адрес (ссылку) одного и того же объекта. А вот переменные s1 и s2 хранят ссылки на очень похожие объекты, но все-таки не на один и тот же объект.

И если вы сравните в коде эти 4 переменные, получите вот такой результат:

Код Вывод на экран
String text = "Привет";
String message = text;
String s1 = text.toUpperCase();
String s2 = text.toUpperCase();
System.out.println(text == message);
System.out.println(text == s1);
System.out.println(s1 == s2); 




true  // адреса равны
false // адреса разные
false // адреса разные


Комментарии (218)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Phoenix Уровень 11
11 октября 2025
оставлю комментарий здесь, чтоб сказать вам что я стану java разработчиком
9 сентября 2025
Спасибо
Anonymous #3584408 Уровень 4
7 августа 2025

String text = "Это очень важное сообщение";
String message = text.toUpperCase();
Минутка наверно ненужных вопросов. Вот мы присвоили новое значение и создали новый объект. Мы как то можем воспользоваться первым значением(String text = "Это очень важное сообщение";) Если я понимаю оно там, так и будет. Или это просто мусор.
motorinatasha Уровень 1
14 августа 2025
думаю можем, ведь оно там осталось существовать - не удалено, как хранилось - так и хранится
Anonymous #3397071 Уровень 4
5 сентября 2025
ну типо ты создаешь такой String text = "Это очень важное сообщение"; String message = text.toUpperCase(); String message1 = text.toLowerCase(); и еще кучу возможных которые мы не прошли, и где-то в проге тебе нужна будет именно String message105 = text.toхзкакойтекстCase(); ну я так ток вижу эту байду
ErenYeag9r Уровень 4
5 августа 2025
Если ты это читаешь, желаю тебе пройти все успешно =)
Anonymous #3516548 Уровень 4
21 июля 2025
baza
Koyo Keyo Уровень 4
8 июля 2025
good
Руслан Уровень 46
12 июня 2025
Метод toUpperCase() возвращает: тот же объект, если вся строка уже в верхнем регистре, новый объект, если произошли изменения. Поэтому да он будет всегда возращать новый обьект если только вы не будете применять метод toUpperCase к словам написанным уже в верхнем регистре
Anonymous #3585174 Уровень 33
27 мая 2025
😎
Javaslavskiy Уровень 41
11 марта 2025

String s1 = text.toUpperCase();
Здесь создается новый объект в куче, т.к. строки immutable - понятно.

String s2 = text.toUpperCase();
А вот здесь не понятно. Почему опять создается новый объект, а не берется из String Pool?
Javaslavskiy Уровень 41
11 марта 2025
Похоже, понял. Это из-за того что toUpperCase() всегда возвращает new String, если изначально в метод не был передан текст в верхнем регистре?
31 марта 2025
Похоже на правду)) String immutable это неизменяемый тип данных, если залезть под капот можно увидеть final модификатор на классе String и массив private final char в котором хранятся символы. Попытка изменить данные приведет к созданию нового объекта. Я не лез под капот метода toUpperCase но подозреваю что просто возвращается новый объект с символами в верхнем регистре.
Aura Уровень 23
19 апреля 2025
Ребят, а вы точно на лекции, подобающей вашим знаниям? =)))) Как лауреат Математических наук обсуждает сложение чисел =)
19 апреля 2025
Aura, не переживай. Обсудить базу - это не зазорно. Комментарии выше, это фундамент, без которого дальше никак. Такие вещи легко могут спросить на собеседовании или вообще принять как само собой разумеющееся. Тебе просто кажется что обсуждается "сложение чисел" как будто что то простое, возможно ты это все уже разобрал, но на самом деле сложная тема особенно для тех кто только погружается в java.
24 февраля 2025
Со строками на самом деле тут очень интересно. Попробуйте выполнить вот такой код =)

String str1 = "HELLO";
String str2 = "HELLO";
System.out.println(str1 == str2);
String str3 = str1.toUpperCase();
System.out.println(str1 == str3);
String str4 = str1.toUpperCase();
System.out.println(str4 == str3);
String str5 = str1.toLowerCase();
String str6 = str5.toLowerCase();
System.out.println(str5 == str6);
Не удивляйтесь сильно. Дело в том, что в Java (как и в C#, кстати) строки интернируются – это значит, что строковые литералы, созданные в коде, помещаются в пул строк (String Pool) в куче. Если строка уже есть в пуле, новая переменная просто ссылается на существующую строку, а не создаёт новую. Поэтому, когда мы пишем String str1 = "HELLO"; и String str2 = "HELLO"; обе переменные указывают на один и тот же объект в памяти. Тогда вы спросите, а почему в следующем примере результат будет false:

String str1 = "Hello";
String str3 = str1.toUpperCase();
String str4 = str1.toUpperCase();
System.out.println(str4 == str3);
А дело в том, что метод toUpperCase() в Java создаёт новую строку в куче, потому что строки в Java неизменяемы (immutable). Однако, есть одна хитрость: если строка уже в верхнем регистре, toUpperCase() вернет ту же самую строку (как в примере с "HELLO"). Но если хотя бы одна буква изменилась, создаётся новый объект. Поэтому str3 и str4 указывают на разные объекты, а следовательно str3 == str4 вернёт false.
Юрий Болотин Уровень 16
1 марта 2025
Хорошее объяснение, спасибо! Можно было ещё упомянуть про создание строки при помощи ключевого слова new (см. рисунок).
Юрий Уровень 20
6 марта 2025
У меня нет подходящих матов чтобы выразить эмоции благодарности за столько достойный вот этот вот.