Переопределение equals() в подклассе класса, который содержит переопределенное equals()

У меня есть класс Point и класс MinesweeperSquare, причем последний является подклассом первого. Если я переопределю метод equals в последнем, например:

if (!(obj instanceof MinesweeperSquare)) {
  return false;
}

FindBugs сообщает, что:

Этот класс определяет метод equals, который переопределяет метод equals в суперклассе. Оба метода равных используют instanceof при определении того, равны ли два объекта. Это чревато опасностью, так как важно, чтобы метод equals был симметричным (другими словами, a.equals(b) == b.equals(a)). Если B является подтипом A, и метод equals A проверяет, что аргумент является экземпляром A, а метод equals B проверяет, что аргумент является экземпляром B, вполне вероятно, что отношение эквивалентности, определяемое этими методами, не является симметричным.

В классе Point я написал:

if (!(obj instanceof Point)) {
  return false;
}

Как написать метод equals в MinesweeperSquare, чтобы метод equals был симметричным?

Обновить

FindBugs не сообщает об ошибках, если я пишу следующее в MinesweeperSquare:

if (o == null || this.getClass() != o.getClass()) {
  return false;
}

person BJ Dela Cruz    schedule 06.02.2012    source источник
comment
Другие ответы уже сделали правильные выводы, но просто чтобы помочь вам при поиске в будущем: это переопределение, а не перезапись.   -  person Jon Skeet    schedule 06.02.2012
comment
возможный дубликат Любая причина предпочесть getClass() вместо instanceof при генерации .equals()?   -  person Raedwald    schedule 15.04.2015


Ответы (3)


В вашем новом методе MinesweeperSquare.equals(Point) всегда будет возвращать false, а Point.equals(MinesweeperSquare) может возвращать true. Хорошо, что вы используете FindBugs для таких вещей. Вы можете использовать getClass() как в определении Point, так и MinesweeperSquare, чтобы проверить, равны ли классы... хотя это тоже сложно.

person Louis Wasserman    schedule 06.02.2012
comment
Почему использование getClass() может быть сложным? Кажется, это хорошая идея. - person BJ Dela Cruz; 06.02.2012
comment
Хитрое, то есть, беспричинное использование рефлексии. - person Louis Wasserman; 06.02.2012

Как вы уже упоминали, если вы используете оператор instanceof в реализации метода equals(), он становится несимметричным. Избавьтесь от instanceof в вашем суперклассе, а также во всех подклассах и попробуйте переопределить метод equals() на основе свойств класса и здравого смысла. Большинство IDE позволяют автоматически генерировать метод equals(), что является хорошей отправной точкой.

person Kris    schedule 06.02.2012

Использование instanceof прекрасно, если все сделано правильно, что довольно сложно без надлежащей лекции. С использованием

this.getClass().equals(that.getClass())

тривиально, но не всегда делает то, что вам нужно. Посмотрите здесь для canEqual.

РЕДАКТИРОВАТЬ

Все это применимо только тогда, когда вы управляете обоими классами, что здесь, похоже, не так. Так что придерживайтесь легкого пути.

person maaartinus    schedule 06.02.2012