Как переопределить метод equals java
Перейти к содержимому

Как переопределить метод equals java

  • автор:

Метод equals() в Java

Основные принципы при проектировании метода equals :

  1. Рефлексивность: для любых не-null объектов x, x.equals(x) должен возвращать true .
  2. Симметричность: для любых не-null объектов x и y, x.equals(y) должен возвращать true , если и только если y.equals(x) возвращает true .
  3. Транзитивность: для любых не-null объектов x, y, и z, если x.equals(y) возвращает true и y.equals(z) возвращает true , тогда x.equals(z) должен возвращать true .
  4. Постоянство: повторный вызов метода equals() должен возвращать одно и тоже значение до тех пор, пока какое-либо значение свойств объекта не будет изменено. То есть, если два объекта равны, то они будут равны пока их свойства остаются неизменными.
  5. Для любых не-null объектов x, x.equals(null) должно возвращать false .

Также стоит обратить внимание на то, что аргументом метода equals всегда является объект класса Object . Например, переопределяя метод для класса Person , мы должны использовать следующую сигнатуру: public boolean equals(Object person) . Зачастую начинающими допускается ошибка и используется сигнатура public boolean equals(Person person) , что приводит к перегрузке метода equals .

Метод equals взаимосвязан с методом hashCode : для одинаковых объектов значение, возвращаемое методом hashCode , должно быть одинаково. Поэтому зачастую переопределяются оба метода.

Отслеживать
ответ дан 20 янв 2016 в 10:25
Pavel Parshin Pavel Parshin
9,229 1 1 золотой знак 27 27 серебряных знаков 48 48 бронзовых знаков

Приведу пример, по которому все будет понятно, также не надо забывать, что при переопределении метода equals() необходимо переопределить метод hashCode(). Если метод equals() возвращает истину для двух объектов, то их хэш-код должен быть одинаковым. Обратное утверждение не верно.

TestClass < private int id; public boolean equals(Object other) < if(!super.equals(other)) return false; if (this == other) return true; if (other == null) return false; if(this.getClass() != other.getClass()) return false; TestClass otherObj = (TestClass)other; return this.id == otherObj.id; >public int hashCode() < return 76+133*id; >> 

Отслеживать
ответ дан 8 дек 2010 в 19:25
Nicolas Chabanovsky Nicolas Chabanovsky
51.3k 87 87 золотых знаков 267 267 серебряных знаков 505 505 бронзовых знаков

Имеем простой класс такой структуры:

class A

Такой метод определения метода equals будет подойдет во многих ситуациях:

public boolean equals(Object other) < // Не строго необходимо, но обычно неплохо для оптимизации if (this == other) return true; if (!(other instanceof A)) return false; A otherA = (A) other; return (someNonNullField.equals(otherA.someNonNullField)) && ((someOtherField == null) ? otherA.someOtherField == null : someOtherField.equals(otherA.someOtherField))); >

Действительно нельзя забывать о методе hashCode. сойдет такая его реализация:

public int hashCode()

Более подробно написано с этой статье от ibm deweloperworks.

Отслеживать
ответ дан 21 янв 2011 в 18:50
1,036 8 8 серебряных знаков 27 27 бронзовых знаков

Вариант использования equals при наследовании. Пусть есть класс точка

public class Point < private int x; private int y; public Point(int x, int y) < this.x = x; this.y = y; >public boolean equals(Object obj) < if (obj == null) return false; // проверка на случай, если сравнение с самим собой if (obj == this) return true; if (obj.getClass() == this.getClass()) < Point point = (Point) obj; if (point.x == this.x && point.y == this.y) return true; >return false; > > 

Теперь пришла в голову мысль написать расширение Point3D и для него также переопределить метод equals

public class Point3D extends Point < private int z; public Point3D(int x, int y, int z) < super(x, y); this.z = z; >public boolean equals(Object obj) < if (super.equals(obj)) < /* * строки не нужны: эти проверки выполняется в базовом классе * if (this == other) return true; * if (other == null) return false; * if(this.getClass() != other.getClass()) return false; */ Point3D p3d = (Point3D) obj; if (p3d.z == this.z) return true; >return false; > > 

Отслеживать
51.3k 87 87 золотых знаков 267 267 серебряных знаков 505 505 бронзовых знаков
ответ дан 20 дек 2010 в 8:09
530 3 3 серебряных знака 4 4 бронзовых знака

Прошу пояснить код. В частности, вот эту строку

if (!super.equals(other)) return false; 

Основной вопрос состоит в следующем. Как Вы думаете, что делает эта строчка процитированного кода? Да, там вызывается метод equals родительского класса. А кто у нас у класса в данном случае родитель? Если верить спецификации, то это java.lang.Object. Значит сначала мы в первой строке Вашего кода вызываем метод equals класса Object. Как Вы думаете, что он делает? Вроде как это известная информация, но для большей достоверности вот цитата из исходников

public boolean equals(Object obj)

То есть он возвращает true только в том случае, когда у нас ссылки на объект совпадают. Если же у нас 2 отдельных объекта, которые хранятся в памяти в разных местах (пусть у них содержимое одинаковое), ссылки на них не совпадают! А что это значит? Это значит, что благодаря строке if(!super.equals(other)) return false; Ваш метод equals будет возвращать true , только если мы будем сравнивать объект сам с собой! Наверное, это не то, чего бы всем хотелось, не так ли? Думаю, эту строку надо убрать и тогда это будет больше похоже на правду. Но вообще каждый раз при написании своего equals надо принимать во внимание тот факт, что когда-то создатели Java и класса java.lang.Object в частности написали условия, которым должен удовлетворять переопределённый метод equals, найти их можно в исходниках, либо здесь.

И ещё заметка относительно hashCode . Вы упомянули только одно из требований котракта по hashCode : если 2 объекта считаются равными (equals возвращает true), то hashCode для них должен возвращать одинаковое значение. Дальше

на самом деле в контракте, найти можно — здесь стоит продолжение: «However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables». То есть надо принимать этот факт во внимание, как и ещё один пункт из этого же контракта.

Как переопределить метод equals java

В Java переопределение — это когда дочерний класс или подкласс имеет специфическую реализацию метода, уже объявленого в родительском классе.

Метод equals() сравнивает две строки. Если данные одного объекта совпадают с данными другого, он возвращает значение true, в противном случае — false. Аннотация @Override сообщает компилятору о переопределении во время компиляции.

@Override public boolean equals(Object o)  if (o == this)  return true; > if (!(o instanceof Example))  return false; > Example example = (Example) o; return Integer.compare(a, example.a) == 0 && Integer.compare(b, example.b) == 0; > 

В этом примере мы выполнили переопределение метода equals() . Сравниваем два объекта, если они равны тогда метод вернет true иначе false.

Есть несколько правил переопределения метода equals().

  1. Использовать оператор == чтобы проверить ссылку на объект, переданную в метод equals().
  2. Используйте оператор instanceof для проверки типа аргумента. Если типы не совпадают вернуть false.
  3. Пройтись по всем значимым полям объектов и сравнить их друг с другом.
  4. Преобразовать аргумент к корректному типу. Т.к. есть метод проверки типа.
  5. Метод equals() сравнивает поля объектов не более, не усложняйте.

Почему в Java нужно переопределять методы equals и hashCode?

В программировании на Java часто возникают ситуации, когда необходимо сравнивать объекты на равенство. Для этого в Java есть два метода: equals() и hashCode() . Они являются методами класса Object , от которого наследуются все классы в Java.

Пример

Возьмем простой пример. У нас есть класс Person с двумя полями: name и age .

public class Person < private String name; private int age; public Person(String name, int age) < this.name = name; this.age = age; >>

Попробуем сравнить два объекта этого класса:

Person person1 = new Person("John", 25); Person person2 = new Person("John", 25); System.out.println(person1.equals(person2)); // false

Здесь ожидается, что два объекта будут равны, так как их имя и возраст совпадают. Однако, метод equals() по умолчанию сравнивает ссылки на объекты, а не их содержимое.

Переопределение метода equals

Чтобы корректно сравнивать объекты по содержимому, необходимо переопределить метод equals() . Это позволяет установить свои правила сравнения объектов.

@Override public boolean equals(Object obj)

Теперь метод equals() сравнивает объекты по содержимому:

Person person1 = new Person("John", 25); Person person2 = new Person("John", 25); System.out.println(person1.equals(person2)); // true

Переопределение метода hashCode

С другой стороны, метод hashCode() важен для корректной работы некоторых структур данных, таких как HashSet , HashMap и т.д. Эти структуры используют хеш-код объекта для быстрого доступа к нему. Если два объекта равны по методу equals() , то их хеш-коды должны быть равны.

@Override public int hashCode()

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

Переопределение методов equals и hashCode в Java

Часто возникают ситуации, когда требуется сравнивать объекты не по ссылке, а по содержимому. Например, имеется класс Book , который содержит поля author , title и year . Если потребуется сравнить две книги не по ссылке, а по автору, названию и году издания, то необходимо переопределить метод equals .

class Book < String author; String title; int year; @Override public boolean equals(Object obj) < if (this == obj) < return true; >if (obj == null || getClass() != obj.getClass()) < return false; >Book book = (Book) obj; return year == book.year && Objects.equals(author, book.author) && Objects.equals(title, book.title); > >

Однако, при переопределении метода equals , необходимо также переопределить и метод hashCode , чтобы поддерживать общий контракт между ними. Если два объекта считаются равными по методу equals , то их хеш-коды также должны быть равными.

@Override public int hashCode()

При переопределении этих методов следует учесть несколько важных моментов:

  1. Симметричность: Если один объект равен другому, то и второй объект должен быть равен первому. Это обеспечивается правильной реализацией метода equals .
  2. Транзитивность: Если первый объект равен второму, и второй объект равен третьему, то первый объект должен быть равен третьему. Это также обеспечивается корректной реализацией метода equals .
  3. Консистентность: Если информация, используемая в методах equals и hashCode , не изменяется, то многократные вызовы этих методов должны возвращать одинаковые результаты.
  4. Не равенство к null: Объект должен быть не равен null . Метод equals должен возвращать false , если его параметр null .
  5. Соответствие между equals и hashCode : Если два объекта равны по методу equals , то и их хеш-коды должны быть равны.

Следуя этим принципам, можно избежать многих проблем при работе с коллекциями и другими структурами данных, которые полагаются на методы equals и hashCode .

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *