检查hashCode()是否为实现equals(Object obj)的有效方法?



我的hashCode方法确保相等的对象具有相等的哈希码。我的实现还保证了对负性为真,因为相等哈希码意味着对象相等。执行如下命令:

   @Override
    public boolean equals(Object obj) {
        if (this == obj) {return true;}
        if (obj == null) {return false;}
        if (getClass() != obj.getClass()) {return false;}
        return (obj.hashCode() == this.hashCode());
    }

似乎是一个显而易见的选择,但我不经常看到这个。这对我来说是个好主意,还是我遗漏了什么?

另外,我不确定这是否相关,但是hashCodeequals方法是在生成的类中(显然是自己生成的)。我提到这一点的原因是要强调这样一个事实,即这些方法不会每次都手工维护。它们位于编译时创建的类中,除非它们所基于的架构发生了变化,否则不打算对其进行更改。

如果,正如问题所说,您的hashCode实现确实保证不相等的对象具有不相等的哈希码,那么原则上您所做的事情没有任何问题。你的equals方法正在检查一个等价于相等的属性,所以行为是预期的。不过,你应该重新检查这个保证;请记住,无论你多么聪明,你只能在int类型中存储32位的信息,这意味着大多数非平凡对象必然会有哈希冲突。

然而,有一些注意事项。首先是清晰:如果你以这种方式实现equals,任何使用你代码的人都必须看看你的hashCode实现,以找出哪些属性决定了平等。其次是速度:如果您的哈希码实现比简单地检查相关属性的相等性(包括该计算中的布尔捷径)要慢得多,那么可能值得在equals函数中重新实现逻辑以避免速度损失。第三是耦合:以这种方式实现equals意味着它依赖于hashCode的属性,并且将来对hashCode的任何更改都必须保留该属性或将逻辑移动到equals

这不是一个好主意。两个相等的对象必须具有相同的哈希码,反之则不成立:具有相同哈希码的两个对象可能不相等。作为一个简单的例子,考虑Long。哈希码返回int,因此不可能用int表示所有可能的long值。这意味着许多Long对象不相等,但具有相同的哈希码。

当且仅当你的对负保证成立,那么你可以用这种方式测试等式。一般情况下,你的对负命题不成立,也不能保证相等。特别是有人可能会重写hashCode()方法,因此您的对负性不再有效。最好使用更传统的相等性检验,比较显著字段。

你的代码是脆弱的,并且严重依赖于你的hashCode()实现的一个非常特定的属性,而这个属性不是一般hashCode()合约的一部分。您总是可以使用不匹配的哈希码来检测不相等。使用相等的哈希码来假定相等并不是好的做法。

有时候(虽然很少),散列码会导致冲突;你可能已经意识到了这一点!

因此,在被比较对象的其他特征(可能除了哈希码)上建立相等性是一个好主意。

不,散列用于在集合中分发对象,它们不是唯一的。例如,集合将使用哈希码来标识放置对象的存储桶。桶本身是一个列表,包含所有具有相似哈希码的对象。目的是为了在顺序不重要的情况下提高查找效率。

使用相同的相等属性构建散列是很重要的,以确保两个语义上相等的对象最终在相同的bucket

相关内容

最新更新