Переменная и объект не одно и то же
Представим два отдельных объекта String, каждый из которых содержит слово Север. Переменная a ссылается на первый объект, переменная b — на второй. Содержимое совпадает, но объекты различны. Для ссылочных значений оператор == проверяет, указывают ли они на один объект, либо являются ли обе ссылки null. Поэтому в нашем примере сравнение a == b даёт false. Это не сообщение о различии букв, а ответ на вопрос об идентичности объектов.
Метод equals у String сравнивает содержимое
Для проверки одинаковой последовательности символов у строк используют equals. В рассматриваемом примере a.equals(b) даст true, поскольку оба объекта содержат одинаковые символы. Теперь добавим переменную c, которой присвоена ссылка a. Новый строковый объект от такого присваивания не появляется: a и c указывают на один и тот же. Поэтому a == c будет true, а содержимое также совпадёт. Бумажная схема со стрелками помогает увидеть различие между копированием ссылки и созданием второго объекта.
Удачный пример не меняет смысл оператора
В некоторых случаях одинаковые строковые литералы могут ссылаться на общий объект. Тогда сравнение через == тоже вернёт true. Это не делает оператор проверкой текста и не позволяет применять его вместо equals к произвольным входным строкам. Полезный вопрос звучит так: какое свойство нужно проверить по условию задачи? Если важны символы, решение должно выражать именно это намерение, а не зависеть от того, как конкретные строки появились в памяти.
Отсутствующее значение требует отдельного внимания
Если a равно null, вызов a.equals(b) не может обратиться к объекту и приведёт к NullPointerException. Для сравнения с учётом возможного null можно использовать Objects.equals. При двух null он возвращает true; при одном null и одной обычной строке — false; в остальных подходящих случаях использует equals. Но технически корректное сравнение не решает вопрос смысла данных. Приложению всё равно нужно определить, допустимо ли отсутствие строки и что оно означает: неизвестное значение, ошибку ввода или другой предусмотренный случай.
Попробуйте на практике
Нарисуйте объекты и ссылки, чтобы предсказать результаты сравнения без догадок.
- Изобразите два отдельных прямоугольника String с одинаковым словом Север. Проведите стрелку a к первому, b ко второму.
- Добавьте стрелку c к тому же прямоугольнику, что и a. Подпишите, что c хранит скопированную ссылку, а не новый объект.
- Запишите результаты a == b, a.equals(b) и a == c. Для каждого укажите, сравниваются ссылки или содержимое.
- Отдельно рассмотрите два отсутствующих значения и сравнение через Objects.equals. Затем замените одно из них обычной строкой и предскажите новый результат.
- Сформулируйте правило выбора проверки для задачи сравнить введённые названия. Укажите, как обрабатывается null, вместо предположения, что его никогда не будет.
Как проверить результат. Для трёх основных проверок получены false, true и true. Вы объясняете ответы через объекты и символы, а случай null рассматриваете отдельно.
Частые вопросы
Если == иногда работает для одинакового текста, зачем менять проверку?
Совпадение результата в частном случае не меняет назначение оператора. Для произвольных строк сравнение содержимого должно быть выражено явно.
Любой метод equals сравнивает объекты по их полям?
Нет. Поведение зависит от класса и его реализации. В этой статье рассматривается String, у которого equals проверяет последовательность символов.
Самостоятельный разбор темы. Содержание конкретной обучающей программы здесь не представлено.