使用哈希码确定对象等价

时间:2016-04-29 04:57:38

标签: java hash equivalence

我们说我有一个代表游戏牌的简单类,名为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合约。然后我在思考,对于Tilexy字段具有相同值的任何两个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的结果?

3 个答案:

答案 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)如果两个对象具有相同的哈希码,则它们可能相等也可能不相等。