什么是实现平等的最佳实践,语义上,而不是技术上。
在Java中,该方法确实应该被认为是“身份平等”,因为它如何与实现集成。请考虑以下事项: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);
如果标识是字段,则第 2 个元素不应向 添加另一个元素,而应返回 from 并具有相同的 。如果您定义(和 hashCode)方法以同时包含 字段和字段,则可能会中断此字段,因为可能包含对具有相同 id 字段的对象的 2 个引用。Foo
id
fooSet.add(...)
Set
false
foo1
foo2
id
Foo.equals
id
stuff
Set
如果您没有将对象存储在(或)中,则不必以这种方式定义方法,但是许多人认为它是不好的形式。如果将来你确实将其存储在一个中,那么事情就会被破坏。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