Привет! Услышав подобный вопрос каждый читатель, не задумываясь ответит:
== - сравнение ссылок, то есть true, если оба объекта указывают на одну ячейку памяти.
equals() - выполняет сравнение значений этих объектов.
Ответ кажется достаточно простым и полным, но давайте подумаем всегда ли это утверждение верно?
В базовой реализации метода equals() для Object происходит сравнение ссылок на объект:
То есть для класса Object, результаты equals() и == одинаковы, оба сравнивают являются ли ссылки на объект одинаковыми.
Как это может повлиять на наш код?
Если наш класс не переопределяет метод equals(), то используется метод equals() ближайшего родительского класса.
Если родительский класс не предоставляет переопределение, по умолчанию используется метод конечного родительского класса Object. То есть этот метод вернет true только тогда, когда две переменные ссылаются на один и тот же объект и если их ссылки одинаковы.
Однако во многих классах JDK, для достижения конкретных сравнений значений метод equals() переопределяется. Например методы equals() в Integer и String.
Давайте посмотрим следующий код:
Из приведенного выше кода видно, что в Integer, для сравнения объект сначала преобразуется в базовый тип int. Таким образом, в этом коде происходит сравнение не двух ссылок на объекты, а сравнение того, равны ли фактические значения этих объектов.
Исходный код реализации eqauls() в String немного сложнее. Я добавил несколько комментариев, чтобы помочь понять:
Из метода equals() в String видно, что он фактически выполняет сравнение на основе ссылок. Если ссылки не равны, он сравнивает являются ли фактические значения равны.
Подведу итог: при использовании equals() и == необходимо осознавать разницу между ними, и особое внимание следует обратить на то, переопределил ли класс метод equals().
Как переопределить метод equals()?
В Java, чтобы правильно переопределить метод equals() необходимо выполнить следующие шаги:
- Проверьте является ли параметр ссылкой на текущий объект, если да, то верните true.
- Проверьте имеет ли параметр правильный тип, если нет верните false.
- Сравните ключевые атрибуты объекта. Если все ключевые атрибуты равны, то верните true, иначе false
Кстати, в Java после переопределения метода equals() переопределяется метод hashCode(). Давайте сделаем это:
Причем здесь hashCode()?
Во первых, переопределение hashCode вместе с equals() это требование спецификации Java. Если два объекта равны посредством equals(), их hashCode так же должен быть одинаковым, чтобы обеспечить согласованное поведение при использовании классов коллекций на основе хэша.
Во вторых, переопределение hashCode может повысить производительность структур данных на основе хэша и уменьшить количество не нужных операций сравнения. По тому, что у объектов с разным хэш-кодом можно быстро определить неравенство и избежать трудоемких сравнений.
Правила переопределения hashCode()
В Java при переопределении метода hashCode() нужно выполнить следующие шаги:
Определите ключевые атрибуты, используемые для оценки равенства объектов, такие как имя и возраст в Student. Выберите подходящий алгоритм хэширования. Обычно битовые операции и простые числа можно использовать для объединения значений ключевых атрибутов для создания хэш-кода.
Убедитесь, что для одинаковых объектов сгенерированный хэш-код одинаков; для неравных объектов попробуйте сделать разные хэш-коды, чтобы повысить производительность хэш-таблицы.
Приведенный выше пример hashCode() использует Objects.hash() для генерации хэш значения. Он может удобно генерировать хэш-код на основе и в большинстве случаев может соответствовать требованиям метода hashCode(). Если необходим более сложный алгоритм хэширования, можно создать собственную реализацию в соответствии конкретными потребностями.
Пишите комментарии, оставляйте лайки и подписывайтесь, если Вам понравилась статья.
Источник: https://medium.com/@tecnicorabi/why-1-1-is-true-but-128-128-is-false-in-java-4ea544e83eef