public boolean equals(Object obj){ return (this == obj); }Т.е. просто сравниваются две ссылки(прямо как оператор "=="). Понятно, что обычно, это не то, что нам надо. Обычно два объекта равны, если основные данные их равны. Чтобы это понимали не только мы, но и компилятор, нам и нужно переопределять метод equals. Существует несколько свойств, которым должен удовлетворять наш переопределенный метод, а именно:
- Симметричность. Т.е. если для каких-либо объектов x и y x.equals(y) возвращает true, то и y.equals(x) должен возвращать true.
- Рефлексивность. Для любого объекта x x.equals(x) должен возвращать true.
- Постоянство. Для любых объектов x и y x.equals(y) возвращает одно и тоже, если информация, используемая в сравнениях, не меняется.
- Транзитивность. Для любых объектов x, y и z, если x.equals(y) вернет true и y.equals(z) вернет true, то и x.equals(z) должен вернуть true.
- Для любого не null объекта x x.equals(null) должен возвращать false.
public class MyClass{ private int x; public MyClass(int x){ this.x = x; } public int getX(){ return x; } }Очевидно, нам надо, чтобы equals возвращал true тогда и только тогда, когда поля x у объектов равны. Что ж, переопределенный метод будет выглядеть примерно так:
@Override public boolean equals(Object obj){ if (this == obj) return true; if (!(obj instanceof MyClass)) return false; MyClass myClass = (MyClass)obj; return (x == myClass.getX()); }Кстати, не забывайте, что тип аргумента должен быть именно Object, а не MyClass. В этом случае это будет уже не переопределение(overriding), а перегрузка(overloading). Именно поэтому, при переопределении следует использовать конструкцию @Override, она проверит, действительно ли ваш метод переопределяет метод суперкласса, и, если это не так, выдаст ошибку.
Пройдемся по коду. Сначала идет проверка на свойство №2(рефлексивность). Затем мы должны сравнить наши поля x, но т.к. в метод передается Object, то нам надо делать приведение типа. А вдруг нам передали не MyClass? Тут нам пригодится instanceof. x instanceof y проверяет: является ли x экземпляром y. Однако конструкция instanceof не только позволяет нам отбросить неверные объекты, но и проверяет наше свойство о null-объектах, т.к. x instanceof y возвращает false, если x - null. Ну а дальше мы непосредственно проверяем наши поля на равенства.
И вроде все бы ничего, переопределили equals, всё работает. Однако, переопределяя equals вы должны позаботиться еще об одном методе класса Object:
public native int hashCode()Существуют следующие соглашения, относительно этих двух методов:
- Всякий раз, когда метод вызывается у одного и того же объекта во время выполнения приложения, он должен возвращать одно и то же число, если используемая информация не изменяется. hashCode может возвращать разные значения для идентичных объектов в различных экземплярах приложения.
- Если два объекта равны, согласно equals, то их hashCode должны возвращать одинаковые значения.
- Обратное требование необязательно. Два неравных объекта могут возвращать одинаковый hashCode. Однако для повышения производительности, лучше, чтобы разные объекты возвращали разные коды.
Метод hashCode используется в hash-коллекциях(например HashSet), и чем меньше будет коллизий(одинаковый код при разных объектах) тем эффективнее эти коллекции будут работать с объектами вашего класса.
В приведенном выше классе MyClass хэш-кодом может выступать само значение x. Это совсем тривиальный случай. А что, если у нас, наряду с числом x, будет например строка s.
Часто используют примерно такой подход:
@Override public int hashCode(){ int code = 11; int k = 7; code = k*code + x; code = k*code + s.hashCode(); return code; }Думаю принцип понятен. Всем удачи!
Комментариев нет:
Отправить комментарий
Примечание. Отправлять комментарии могут только участники этого блога.