Сравнение параметров объектов java
О сравнении объектов с помощью методов Java equals() и hashcode()
Без equals() и hashcode() нам пришлось бы создавать громоздкие сравнения «if», сопоставляя каждое поле с объектом. Что сделало бы исходный код запутанным.
Переопределение equals() и hashcode() в Java
Ниже приведен метод equals() в классе Object. Метод проверяет, совпадает ли текущий экземпляр с ранее переданным объектом.
Если equals() и hashcode() не переопределены, вместо них вы увидите приведенные выше методы. В этом случае методы не выполняют задачу equals() и hashcode() — проверку, имеют ли два (или более) объекта одинаковые значения.
Сравнение объектов с помощью метода equals ()
Мы используем метод equals() для сравнения объектов в Java. Чтобы определить, совпадают ли два объекта, equals() сравнивает значения атрибутов объектов:
Во втором сравнении equals() проверяет, является ли переданный объект пустым, или его тип принадлежит к другому классу. Если это другой класс, то объекты не равны.
Наконец, equals() сравнивает поля объектов. Если два объекта имеют одинаковые значения полей, то объекты одинаковы.
Анализ сравнений объектов
Рассмотрим результаты этих сравнений в методе main(). Сначала мы сравниваем два объекта Simpson:
Объекты идентичны, поэтому результат будет true.
Затем снова сравниваем два объекта Simpson:
Сравним объект Simpson и экземпляр класса Object :
В этом случае результат будет false, потому что типы классов разные.
equals () или ==
Может показаться, что оператор == и метод equals() делают то же самое. Но на самом деле они работают по-разному. Оператор == сравнивает, указывают ли две ссылки на один и тот же объект.
Идентификация объектов с помощью hashcode ()
Мы используем метод hashcode() для оптимизации производительности при сравнении объектов. Выполнение hashcode() возвращает уникальный идентификатор для каждого объекта в программе. Что значительно облегчает реализацию.
Использование equals() и hashcode() с коллекциями
Интерфейс Set отвечает за то, чтобы в подкласс Set не было повторяющихся элементов. Ниже перечислены часто используемые классы, реализующие интерфейс Set:
В приведенном ниже примере для добавления нового элемента в объект HashSet используется метод add. Перед добавлением нового элемента HashSet проверяет, существует ли элемент в данной коллекции:
Если объект тот же, новый элемент не будет вставлен.
Хэш-коллекции
Рекомендации по использованию equals() и hashcode()
Для объектов, имеющих один и тот же уникальный идентификатор hashcode, нужно использовать только equals(). Не нужно выполнять equals(), когда идентификатор hashcode отличается.
Таблица 1. Сравнение хэш-кодов
Если сравнение hashcode() … | Тогда … |
возвращает true | выполнить equals () |
возвращает false | не выполнять equals () |
Этот принцип используется в коллекциях Set или Hash для повышения производительности.
Правила сравнения объектов
Таблица 2. Сравнение объектов с помощью hashcode()
Когда сравнение хэш-кодов возвращает… | метод equals() должен возвращать … |
True | true или false |
False | False |
Таблица 3. Сравнение объектов с помощью equals()
Когда метод equals() возвращает … | метод hashcode() должен возвращать… |
True | True |
False | true или false |
Выполните задание на использование equals() и hashcode()!
Для начала внимательно изучите приведенный ниже код:
Проанализируйте код, угадайте результат, а затем запустите программу. Ваша цель заключается в том, чтобы улучшить навыки анализа кода,усвоить основные концепции Java и сделать создаваемый код более эффективным. Выберите свой вариант, прежде чем проверять правильный ответ, который приведен ниже.
Что сейчас произошло? Понимание equals() и hashcode()
В первом сравнении equals() результат верен, потому что метод hashcode() возвращает одно и то же значение для обоих объектов.
Обратите внимание, что размер коллекции задан для хранения трех объектов Simpson. Рассмотрим это более подробно.
Первый объект в наборе будет добавлен в коллекцию:
Следующий объект также будет добавлен, поскольку имеет отличное от предыдущего объекта значение:
Последний объект Simpson имеет то же значение, что и первый. В этом случае объект не будет вставлен:
Объект overridenHomer использует другое значение хэш-кода из обычного экземпляра Simpson («Homer»). По этой причине этот элемент будет вставлен в коллекцию:
Ответ
Распространенные ошибки использования equals() и hashcode()
Что нужно помнить о equals() и hashcode()
Пожалуйста, опубликуйте ваши отзывы по текущей теме статьи. За комментарии, подписки, лайки, отклики, дизлайки огромное вам спасибо!
Как сравнить 2 объекта
Как без лапша-кода сравнить 2 объекта?
Например такой класс
и чтобы не писать что-то типа
5 ответов 5
У вас должно получиться что-то похожее на это:
Можно будет сравнивать так:
Если хочется универсальный метод, то можно как-то так, рефлекшеном, но Вы наверняка сами знаете, что это медленно и все такое:
PS: В целом не рекомендую использовать такой подход, уж лучше сгенерировать метод через ide
С помощью библиотеки Apache Commons Lang и рефлексии можно даже в одну строчку
Всё ещё ищете ответ? Посмотрите другие вопросы с метками java или задайте свой вопрос.
Похожие
Подписаться на ленту
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
дизайн сайта / логотип © 2021 Stack Exchange Inc; материалы пользователей предоставляются на условиях лицензии cc by-sa. rev 2021.9.17.40238
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Сравнение объектов в Java
Узнайте о сравнении объектов в Java.
1. введение
Сравнение объектов является важной особенностью объектно-ориентированных языков программирования.
В этом уроке мы рассмотрим некоторые функции языка Java, которые позволяют нам сравнивать объекты. Кроме того, мы рассмотрим такие функции во внешних библиотеках.
2.1. Примитивы
Для примитивных типов быть одинаковым означает иметь равные значения:
Благодаря автоматической распаковке это также работает при сравнении примитивного значения с его аналогом типа оболочки :
2.2. Объекты
Допустим, мы хотим сравнить два типа Integer wrapper с одним и тем же значением:
Теперь давайте посмотрим, что происходит, когда мы используем Integer#значение метода factory:
В этом случае они считаются одинаковыми. Это связано с тем, что метод valueOf() хранит Целое число в кэше, чтобы избежать создания слишком большого количества объектов-оболочек с одним и тем же значением. Поэтому метод возвращает один и тот же экземпляр Integer для обоих вызовов.
Java также делает это для String :
Наконец, две null ссылки считаются одинаковыми, в то время как любой объект, не являющийся null , будет считаться отличным от null :
Конечно, поведение операторов равенства может быть ограничивающим. Что делать, если мы хотим сравнить два объекта, сопоставленные с разными адресами, и все же считать их равными на основе их внутренних состояний? Мы увидим это в следующих разделах.
3. Метод Object#equals
Во-первых, давайте посмотрим, как он ведет себя для существующих объектов, таких как Integer :
Следует отметить, что мы можем передать объект null в качестве аргумента метода, но, конечно, не в качестве объекта, на котором мы вызываем метод.
Мы можем использовать метод equals() с нашим собственным объектом. Допустим, у нас есть Человек класс:
Мы можем переопределить метод equals() для этого класса, чтобы мы могли сравнить два Person s на основе их внутренних данных:
4. Объекты#равны Статическому методу
То равняется() метод Объекты вспомогательный класс решает эти проблемы. Он принимает два аргумента и сравнивает их, также обрабатывая нулевой ценности.
Давайте снова сравним Человека объекты с:
Это может быть очень удобно. Допустим, мы хотим добавить необязательную дату рождения в наш Человек класс:
Однако, если мы добавим в наш класс много полей, допускающих обнуление, это может стать действительно грязным. Использование метода объекта#equals в нашей реализации equals() намного чище и улучшает читаемость:
5. Сопоставимый интерфейс
Логика сравнения также может использоваться для размещения объектов в определенном порядке. | Сопоставимый интерфейс позволяет нам определять порядок между объектами , определяя, является ли объект больше, равен или меньше другого.
Допустим, в нашем классе Person мы хотим сравнить объекты Person по их фамилии:
6. Интерфейс компаратора
Компаратор аналогичен; однако он отделен от определения класса. Поэтому мы можем определить столько Компараторов , сколько нам нужно для класса, где мы можем предоставить только одну Сопоставимую реализацию.
Давайте теперь отсортируем Список людей, использующих этот Компаратор :
В интерфейсе Comparator есть другие методы, которые мы можем использовать в нашей реализации compareTo() :
В этом случае мы сначала сравниваем фамилии, а затем имена. Затем мы сравниваем даты рождения, но поскольку они обнуляются, мы должны сказать как с этим справиться поэтому мы даем второй аргумент, говорящий, что их следует сравнивать в соответствии с их естественным порядком, но с нулевыми значениями, идущими последними.
7. Apache Commons
7.1. Метод ObjectUtils#NotEqual
Давайте повторно используем наши примеры String :
7.2. Метод сравнения объектов#
Давайте еще раз посмотрим, как использовать Strings :
8. Гуава
8.1. Объекты#равный метод
8.2. Методы сравнения
8.3. Класс сравнительной цепи
9. Заключение
В этой статье мы рассмотрели различные способы сравнения объектов в Java. Мы рассмотрели разницу между одинаковостью, равенством и упорядоченностью. Мы также рассмотрели соответствующие функции в библиотеках Apache Commons и Guava.
Java Challengers #4: Сравнение объектов с equals() и hashCode()
В преддверии запуска нового потока по курсу «Разработчик Java» мы продолжаем перевод серии статей Java Challengers, предыдущие части которых можно прочитать по ссылкам ниже:
В этой статье вы узнаете, как связаны между собой методы equals() и hashCode() и как они используются при сравнении объектов.
Без использования equals() и hashCode() для сравнения состояния двух объектов нам нужно писать много сравнений » if «, сравнивая каждое поле объекта. Такой подход делает код запутанным и трудным для чтения. Работая вместе, эти два метода помогают создавать более гибкий и согласованный код.
Исходный код для статьи находится здесь.
Переопределение equals() и hashCode()
Переопределение метода (method overriding) — это приём при котором поведение родительского класса или интерфейса переписывается (переопределяется) в подклассе (см. Java Challengers #3: Полиморфизм и наследование, анг.). В Java у каждого объекта есть методы equals() и hashCode() и для правильной работы они должны быть переопределены.
Это native — метод, который написан на другом языке, таком как Си, и он возвращает некоторый числовой код, связанный с адресом памяти объекта. (Если вы не пишете код JDK, то не важно точно знать, как работает этот метод.)
Примечание переводчика: про значение, связанное с адресом сказано не совсем корректно (спасибо vladimir_dolzhenko). В HotSpot JVM по умолчанию используются псевдослучайные числа. Описание реализации hashCode() для HotSpot, есть здесь и здесь.
Сравнение объектов с equals()
Метод equals() используется для сравнения объектов. Чтобы определить одинаковые объекты или нет, equals() сравнивает значения полей объектов:
Во втором сравнении проверяется, является ли переданный объект null и какой у него тип. Если переданный объект другого типа, то объекты не равны.
Наконец, equals() сравнивает поля объектов. Если два объекта имеют одинаковые значения полей, то объекты совпадают.
Анализ вариантов сравнения объектов
Затем снова сравниваем два объекта Simpson :
Наконец, давайте сравним объект Simpson и экземпляр класса Object :
equals() в сравнении с ==
На первый взгляд кажется, что оператор == и метод equals() делают одно и то же, но, на самом деле, они работают по-разному. Оператор == сравнивает, указывают ли две ссылки на один и тот же объект. Например:
Во следующем примере используем переопределенный метод equals() :
Идентификация объектов с hashCode()
Использование equals() и hashCode() с коллекциями
Классы, реализующие интерфейс Set (множество) должны не допускать добавления повторяющихся элементов. Ниже приведены некоторые классы, реализующие интерфейс Set :
Посмотрим на часть реализации метода add() в HashSet :
Перед добавлением нового элемента HashSet проверяет, существует ли элемент в данной коллекции. Если объект совпадает, то новый элемент вставляться не будет.
Рекомендации по использованию equals() и hashCode()
Таблица 1. Сравнение хэш-кодов
Этот принцип в основном используется в коллекциях Set или Hash по соображениям производительности.
Правила сравнения объектов
Таблица 2.Сравнение объектов с hashCode()
Таблица 3. Сравнение объектов с equals()
Решите задачку на equals() и hashCode()
Для начала, внимательно изучите следующий код :
Сначала проанализируйте код, подумайте, какой будет результат. И только потом запустите код. Цель в том, чтобы улучшить ваши навыки анализа кода и усвоить основные концепции Java, чтобы вы могли сделать свой код лучше.
Какой будет результат?.
Что произошло? Понимание equals() и hashCode()
Первый объект в наборе будет вставлен как обычно:
Следующий объект также будет вставлен в обычном порядке, поскольку содержит значение, отличное от предыдущего объекта:
Наконец, следующий объект Simpson имеет то же значение имени, что и первый объект. В этом случае объект вставляться не будет:
Ответ
Правильный ответ — B. Вывод будет:
Частые ошибки с equals() и hashCode()
Что нужно помнить о equals() и hashCode()
Изучите больше о Java
Традиционно жду ваши комментарии и приглашаю на открытый урок, который уже 18 марта проведет наш преподаватель Сергей Петрелевич
В этой статье мы рассмотрим методики сравнения объектов в Java и какие инструменты нам для этого понадобятся. Как вы сможете понять из этой статьи задача сравнения объектов не такая уж, и тривиальная и выработать единый и универсальный подход для сравнения всех объектов едва ли представляется возможным. Сравнение объектов в Java выполняется с помощью оператора сравнения == и метода equals(). Если оператор сравнения можно использовать с примитивами, то метод equals() используется только с экземплярами классов. При их использовании проверяется ссылаются ли переменные на один и тот же объект в памяти. Рассмотрим пример:
Переменная ob1 содержит в себе ссылку на объект класса Object, а переменная ob2 просто ее копирует при объявлении, в итоге две переменных ссылаются на один и тот же объект в памяти, что при сравнении этих двух переменных всегда возвращается true. Другой пример:
Теперь при объявлении каждой из переменных вызывается оператор new, который для каждой из них создает свой экземпляр класса Object, поэтому при сравнении этих двух переменных каждый раз возвращается false, потому что обе переменные указывают на разные объекты в разных участках памяти. Давайте теперь сравним что-то более конкретное, например, две строки:
Как видите поведение метода equals() для класса String несколько отличается. Это происходит по одной простой причине, метод equals() определен в классе Object, поэтому все классы в Java его наследуют и вольны переопределять, что и было сделано в классе String. Как видите методом equals() проверяются на соответствие символы двух строк, если они совпадают, то метод возвращает true. Перед тем как приступить к переопределению метода equals() и комплексному сравнению объектов созданных нами классов, мы рассмотрим инструменты, которые нам для этого понадобятся: оператор instanceof и метод getClass().
Оператор instanceof.
Оператор instanceof служит для проверки к какому классу принадлежит объект. a instanceof B возвращает истину, если в переменной a содержится ссылка на экземпляр класса B, подкласс B (напрямую или косвенно, иначе говоря, состоит в иерархии наследования классов) или реализует интерфейс B (так же напрямую или косвенно). Давайте подробнее рассмотрим, как это работает на примере:
Иерархия классов очень проста, главный класс A, классы B и C от него наследуются. Посмотрим как поведет себя оператор instanceof с нашими классами:
Первая проверка возвращает true, потому что aB является экземпляром класса B. Вторая проверка возвращает true, потому что aB является подклассом A. И последний вызов оператора instanceof возвращает false, несмотря на то, что оба класса B и С наследуются от A, это совершенно разные классы. На самом деле, ситуация с последним вызовом оператора instanceof сложнее, чем может показаться. Типом переменной aB является класс A, иначе говоря, она может содержать в себе любой из трех классов, в том числе класс C и компилятор это проверяет, если возникнет ситуация, при которой оператор instanceof не сможет ни при каких условиях вернуть true – возникнет ошибка компиляции:
Переменная с типом класса B на данном этапе нашей иерархии классов ни при каких условиях не может содержать в себе ссылку на класс С, поэтому возникает ошибка компиляции. Опять же, есть один нюанс, это правило не работает для интерфейсов:
Как мы видим связи между классом A и интерфейсом I нет никакой, и тем не менее ошибки компиляции не возникает, а оператор instanceof возвращает false. Всегда существует вероятность в будущем реализации интерфейса тем или иным классом, поэтому в данном случае компилятор идет нам уступки. Если же класс реализует интерфейс, то оператор instanceof вернут true:
Как упоминалось ранее все классы наследуются от класса Object либо напрямую, либо через родительский класс, поэтому a instanceof Object всегда будет возвращать true за исключение одной ситуации:
Так вот, a instanceof Object всегда будет возвращать true, только если a не равна null.
Метод getClass().
Метод getClass() возвращает класс объекта, содержащий сведения об объекте: public final Class getClass(). Как Вы можете заметить метод является конечным и переопределению не подлежит. С методом getClass() все обстоит несколько проще и очевидней нежели с оператором instanceof.
Как видите, метод прост и эффективен, ровно до тех пор, пока не применен механизм наследования. При наследовании этот метод становится менее полезным. Это утверждение может многим показаться спорным, но мы к нему еще вернемся в конце главы, когда будем размышлять о том, каким должен быть идеальный метод для сравнения объектов.
Метод equals().
Почему мы так подробно рассматривали оператор instanceof? Потому что это будет наша первая проверка, хотя многие предпочитают использовать метод getClass(), но обо всем по порядку. Как говорилось выше, метод equals() содержится в классе Object и наследуется всеми классами, в которых мы вправе его переопределить, давайте это сделаем:
В нашем примере метод equals() всегда будет возвращать true, что и было продемонстрировано. Не смотря на то, что в памяти было создано два объекта Eq, метод equals() все равно вернул истину. Единственное на что хотелось бы обратить внимание, это аннотация @Override. Она используется для явного обозначения переопределения метода, если бы мы допустили ошибку и просто перегрузили метод, то с этой аннотацией у нас бы возникла ошибка компиляции:
В примере выше метод equals() перегружен (в качестве параметра методу передается класс Eq вместо Object), что и приводит к ошибке компиляции. Настало время рассмотреть более сложный пример:
В классе Car происходит более комплексная проверка на равенство объектов: первоначально оператор instanceof проверяет, принадлежат ли классы одной иерархии наследования, если нет, то объекты не равны, если принадлежат, то проверка идет по строковому полю name, при совпадении этого поля (ну или при совпадении названия машин) объекты будут равны. Рассмотрим пример сравнения объектов с помощью метода getClass():
Так как метод equals() является одним из ключевых в Java, существует ряд правил касающихся его работы:
Метод hashCode()
Хэш-код — это целое число, генерируемое на основе конкретного объекта. Метод hashCode() тесно взаимосвязан с методом equals() (если x и y – разные объекты, то с высокой долей вероятности должны различаться результаты вызовов hashCode() для этих объектов), поэтому Oracle рекомендует при переопределении метода equals() так же переопределять метод hashCode():