我们说我有一个代表游戏牌的简单类,名为Tile
:
public class Tile {
public final int x;
public final int y;
public final int plane;
public Tile(int x, int y, int plane) {
this.x = x;
this.y = y;
this.plane = plane;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj instanceof Tile) {
Tile other = (Tile) obj;
return other.x == x && other.y == y && other.plane == plane;
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(x, y, plane);
}
}
作为一个负责任的公民,我实现了hashCode
方法,以确保等效对象的哈希码相等,每个equals
合约。然后我在思考,对于Tile
,x
和y
字段具有相同值的任何两个plane
对象,哈希码 - 正如他们应该 - 将等于。那么为什么不使用 来检查对象是否等价,而不是单独比较字段的值?
更明确地说,为什么不替换:
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj instanceof Tile) {
Tile other = (Tile) obj;
return other.x == x && other.y == y && other.plane == plane;
}
return false;
}
简单地说:
@Override
public boolean equals(Object obj) {
return obj == this || obj != null && obj.hashCode() == hashCode();
}
我的一部分认为这是不好的做法。这几乎就像循环推理一样。但是,我想不出一个有效的,实际的理由,为什么这是一个不好的做法。
简而言之:是否适合使用hashCode
的结果来确定equals
的结果?
答案 0 :(得分:6)
没有。可以想象如下:对于三个Tile
s的每个组合,有2 ^ 32 * 2 ^ 32 * 2 ^ 32 = 2 ^ 96个不同的可能int
s。
只有2 ^ 32个hashCode
s。
因此,对于任何给定的Tile
,将有2 ^ 64 个不同的可能Tile
具有相同的哈希码。
简而言之:哈希码并非唯一。许多对象碰巧具有相同的哈希码,即使它们不相等。
(一般情况下,请务必记住return 0;
是hashCode()
的有效实现。)
答案 1 :(得分:2)
查看hashCode()
的合同:
如果两个对象根据不相等而不是必需的 equals(java.lang.Object)方法,然后调用hashCode方法 两个对象中的每一个都必须产生不同的整数结果。
两个“相等”对象应该具有相同的哈希码。
两个“不等”对象可以具有相同的哈希码。
答案 2 :(得分:1)
因为2个对象可能具有相同的散列函数,但可能不相等。
这样想。在哈希表中,计算对象的哈希码以找到对象将在其中的桶。存储桶可能具有多个具有相同哈希码的对象。它是equals方法,它将从存储桶中对象的列表(集合)中找到对象。
Java equals() and hashCode() Contract
在上面提到的链接中,请转到“由hashCode()引起的问题”部分并查看第二点。
以下是它的片段
1)如果两个对象相等,则它们必须具有相同的哈希码。
2)如果两个对象具有相同的哈希码,则它们可能相等也可能不相等。