繁体   English   中英

如果我不想将我的对象用作哈希表中的键,为什么两个相等的对象应返回相等的哈希码?

[英]Why should two equal objects return equal hash codes if I don't want to use my object as a key in a hash table?

这就是Object.hashCode()的Java文档所说的:

如果根据equals(Object)方法,两个对象相等,则在两个对象中的每个对象上调用hashCode方法必须产生相同的整数结果。

但是他们没有解释为什么两个相等的对象必须返回相等的哈希码。 为什么Oracle工程师决定覆盖equals时必须覆盖hashCode

equals的典型实现不调用hashCode方法:

@Override
public boolean equals(Object arg0) {
    if (this == arg0) {
        return true;
    }
    if (!(arg0 instanceof MyClass)) {
        return false;
    }
    MyClass another = (MyClass) arg0;
    // compare significant fields here
}

有效的Java(第二版)中,我读到:

第9项:覆盖等于时,始终覆盖hashCode。

错误的常见来源是无法覆盖hashCode方法。 您必须在覆盖等于的每个类中覆盖hashCode。 否则,将导致违反Object.hashCode的常规协定,这将阻止您的类与所有基于哈希的集合(包括HashMap,HashSet和Hashtable)一起正常运行。

假设我不需要将MyClass用作哈希表的键。 在这种情况下,为什么需要覆盖hashCode()

当然,当您有一个仅由您自己编写的小程序,并且每次使用外部lib时都检查它不依赖hashCode()则可以忽略所有这些警告。 但是,随着软件项目的增长,您将使用外部库,并且这些库将依赖hashCode()并且您将浪费大量时间来寻找错误。 或者在较新的Java版本中,其他一些类也使用hashCode() ,您的程序将失败。

因此,只需实施此规则并遵循此简单规则,就会容易得多,因为现代IDE只需单击一下即可自动生成equalshashCode

更新一个小故事 :在工作中,我们在许多类中也忽略了此规则,仅实现了所需的多数为equalscompareTo 有一天,会发生一些奇怪的事情,因为一个程序员在GUI中使用了Hash * -Class,而我们的对象没有遵循此规则。 最后,学徒需要用equals搜索所有类,并必须添加相应的hashCode方法。

如文本所述,这违反了使用中的总合同。 当然,如果您从未在任何需要哈希码的地方使用它,没有人会强迫您实现它。

但是,如果将来有一天需要怎么办? 如果其他开发人员使用了该类怎么办? 这就是为什么必须同时执行这两个合同的原因,因此不会造成混乱。

显然,如果没有人调用您的类的hashCode方法,则没人会知道它与equals不一致。 您能保证在项目期间(包括维护年限),没有人需要从列表中删除重复的对象或将一些额外的数据与对象相关联吗?

您可能更安全地实现hashCode以便与equals保持一致。 并不是特别困难,始终返回0已经是有效的实现。

(尽管不要只返回0)

必须重写hashCode以与equals一致的原因是因为使用hashCode的原因和方式。 哈希码用作值的替代,以便在将键值映射到某些对象时,可以使用哈希来提供具有合理空间的近恒定查找时间。 当两个值比较相等时(即,它们是相同的值),那么当它们用作哈希集合的键时,它们必须映射到相同的对象。 这就要求它们具有相同的哈希码才能到达它们。

您必须适当地覆盖hashCode因为该手册指出您必须这样做。 它说您必须这样做,因为已经做出了这样的决定:库可以假定您满足该合同,因此在使用您提供的值作为函数实现中的键时,它们(和您)可以具有哈希的性能优势。

常见的用法表明,对于equals()compareTo() (如果要对MyClass实例进行排序)以及使用哈希表,都需要// compare significant fields here的逻辑。 因此,将此逻辑放入hashCode()并让其他方法使用哈希码是有意义的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM