каковы наилучшие методы реализации equals, семантически, а не технически.
В Java метод equals
действительно следует рассматривать как " identity equals" из-за того, как он интегрируется с реализациями Collection
и Map
. Рассмотрим следующее:
public class Foo() {
int id;
String stuff;
}
Foo foo1 = new Foo(10, "stuff");
fooSet.add(foo1);
...
Foo foo2 = new Foo(10, "other stuff");
fooSet.add(foo2);
Если Foo
identity является полем id
, то второе fooSet.add(...)
не должно не добавлять еще один элемент в Set
, но должно возвращать false
, так как foo1
и foo2
имеют одинаковые id
. Если вы определяете метод Foo.equals
(и hashCode) для включения оба поля id
и stuff
, это может быть нарушено, поскольку Set
может содержать 2 ссылки на объект с одним и тем же полем id.
Если вы не храните свои объекты в Collection
(или Map
), то вам не нужно определять метод equals
таким образом, однако многие считают это дурным тоном. Если в будущем вы сделаете сохранение его в Collection
, тогда все будет сломано.
Если мне нужно проверить равенство всех полей, я обычно пишу другой метод. Что-то вроде equalsAllFields(Object obj)
или что-то в этом роде.
Тогда вы бы сделали что-то вроде:
assertTrue(obj1.equalsAllFields(obj2));
Кроме того, рекомендуется не определять equals
методы, учитывающие изменяемые поля. Проблема также усложняется, когда мы начинаем говорить об иерархии классов. Если дочерний объект определяет equals
как комбинацию своих локальных полей и базового класса equals
, то его симметрия нарушена:
Point p = new Point(1, 2);
// ColoredPoint extends Point
ColoredPoint c = new ColoredPoint(1, 2, Color.RED);
// this is true because both points are at the location 1, 2
assertTrue(p.equals(c));
// however, this would return false because the Point p does not have a color
assertFalse(c.equals(p));
Еще одно чтение, которое я настоятельно рекомендую, — это раздел «Подводный камень № 3: определение равенства с точки зрения изменяемых полей» на этой замечательной странице:
Как написать метод равенства на Java
Некоторые дополнительные ссылки:
Да, и просто для потомков, независимо от того, какие поля вы выбрали для сравнения для определения равенства, вам нужно использовать одни и те же поля в расчете hashCode
. equals
и hashCode
должны быть симметричны. Если два объекта равны, они должны иметь одинаковый хэш-код. Обратное не обязательно верно.
person
Gray
schedule
16.03.2012
When writing unit-tests, I often face the situation when equals() for some object in tests -- in assertEquals -- should work differently from how it works in actual environment.
Зачем тебе это? - person helpermethod   schedule 16.03.2012