关于Person的定义:
public class Person {
private int id;
private int characteristics;
public boolean equals (Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof Person) {
if (id == ((Person) obj).id) {
return true;
} else if (characteristics == ((Person) obj).characteristics) {
return true;
}
}
return false;
}
}
如果Person
返回a
,则b
个对象a.equals(b)
和true
必须具有相同的哈希码,我应该如何实现hashCode
方法?
溶液
根据Java的等价协议,我的equals
方法实现不正确: transitivity 不满足:a.id = 1
,a.characteristic = 2
,b.id = 1
,{ {1}},b.characteristic = 3
,c.id = 2
; c.characteristic = 3
,a.equals(b) == true
,但b.equals(c) == true
。
答案 0 :(得分:5)
由于您的类在各自的id
或characteristics
字段相等时认为对象相等,因此您可合理使用的唯一哈希码是所有实例的常量值:
public int hashCode() {
return 0;
}
这将使基于散列的查找执行得非常糟糕。
equals()
中的任何一项或测试通常都是一个坏主意;对象实际上不是相等,是吗?也许他们只是“相互匹配?”也许您应该考虑单独留下equals()
并实施其他比较方法。
正如托马斯所指出的,你的equals()
测试不是传递性的;如果a.equals(b) && b.equals(c)
为真,那么a.equals(c)
必须为真。对于您的重载,这不为true,因此您的实现违反了equals()
的合同。我强烈建议您以不同的方法实施此测试,并单独留下equals()
。
答案 1 :(得分:1)
这是为您的班级自动生成的intellij-idea:
@Override
public int hashCode() {
int result = id;
result = 31 * result + characteristics;
return result;
}
经过几次重构:
@Override
public int hashCode() {
return 31 * id + characteristics;
}
记录中,是仅仅是我还是你的equals()
被打破了?如果id
s或characteristics
相等,则认为两个对象相等,但不一定两者都相同。这意味着您的平等不是 transitive ,一旦您的对象进入荒野,这可能会产生意想不到的副作用。
这是一个不错的实现:
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Person)) {
return false;
}
Person person = (Person) o;
return characteristics == person.characteristics && id == person.id;
}
答案 2 :(得分:0)
如果具有相同的id
意味着始终具有相同的characteristics
(这似乎使equals()
有效),那么您的哈希码可以单独使用characteristics
:
@Override
public int hashCode() {
return characteristics;
}
如果情况并非如此,您可能需要重新考虑使用Java相等来表达这种关系,正如@cdhowie所暗示的那样。