【问题标题】:Why doesn't my hashmap work? My object has the property that hashCode() equality implies equals(...) equality [closed]为什么我的哈希图不起作用?我的对象具有 hashCode() 相等意味着 equals(...) 相等的属性[关闭]
【发布时间】:2017-11-17 12:18:21
【问题描述】:

为什么我的 Java HashMap 不起作用?我的对象具有.equals 相等意味着hashCode 相等的属性。

您可以假设我在将对象添加到HashMap 之后正在修改对象的字段。

【问题讨论】:

  • 如底部this question 的回答中所述:如果您使用基于散列的集合,则需要“最终”散列码
  • 您是否使用相同的对象作为您的 hashmap 的键和值?如果是这样,您要归档什么?通常,在将条目添加到 hashmap 后,根本不应该更改键。
  • 所需的属性是对象相等意味着哈希码相等,而不是相反。如果对象用作键并且该字段构成哈希码或相等计算的一部分,则不能修改该对象的字段。
  • 你的代码在哪里?如果没有机会看到您迄今为止所做的尝试,我们怎么能知道您可能做错了什么?
  • 嗯,不需要代码。只是试图通过其他人的搜索结果来改善这种情况。我会将答案标记为已接受,这样它就不会出现在您的“未决问题”供稿中。

标签: java hashmap hashtable hashset


【解决方案1】:

您可以假设我在将对象添加到 HashMap 后正在修改对象的字段。

这就是为什么。

Javadoc says:

注意:如果将可变对象用作映射键,则必须非常小心。 如果对象的值以影响等于比较的方式更改而对象是映射中的键,则映射的行为未指定

“未指定”的意思是“可能不工作”,所以当它不工作时你不应该感到惊讶。

【讨论】:

    【解决方案2】:

    如果您在将对象添加到HashMap 之后 改变(更改)对象,则您的对象将位于错误的存储桶中。这是因为即使对象已更改,在更改发生后对象也不会“重新归档”到(新的)正确存储桶中。

    因此,remove 之类的方法将无法找到您的对象,因为该对象位于过时的存储桶中。

    真正推动这个家(对我来说)是当对象最初添加到HashMap 时,哈希值(一个 int)与条目一起存储。这意味着哈希是一个相对静态的属性,很少(从不)更新。

    可能的解决方法包括:

    1. 如果您遍历hashmap 中的每个条目并从这些条目创建一个新的HashMap,它可能会起作用。这在性能方面可能很糟糕,但可能是最正确的做法。

    2. 不要在 hashCode 函数中包含正在更改的字段。虽然不是很好(利用未指定的编译器行为充其量是有风险的业务),但它往往会起作用,因为您只会遇到冲突,这只会影响性能,而不是正确性。您仍然需要在 .equals(Object obj) 方法中包含有问题的字段,否则您最终可能会删除错误的对象。

    3. 算法解决方案:找到一种方法在对象中存储不同的数据,该对象充当恒定的键。例如,在我的应用程序中,我使用整数字段跟踪对象的“年龄”。每次我在应用程序中达到一定的时间时,我都会增加所有键的年龄。如果某件事的时间超过 50 个单位,那么我可以合理地丢弃键值对。或者,我可以更改对象以存储对象的“出生时间”。也就是说,如果在创建对象时应用程序是 1000 个时间单位,我将存储数字 1000。然后,为了确定对象的年龄,我可以将当​​前“时间”与出生时间进行比较,并丢弃如果差值 > 50,则为对象。

    【讨论】:

    • 仅从 hashCode 中排除可变字段并不能解决问题。是的,hashCode 会找到正确的存储桶,但检索逻辑需要断言它是正确的对象(因为多个键可能映射到该存储桶)并且它将使用 equals 来验证这一点。如果 equals 仍然使用可变字段,它将无法识别它是预期的键。
    • 由于等号在比较中包含了键,所以它仍然可以工作。我已经更新了我的答案,以更严肃地反映利用未定义的编译器行为可能会让你陷入困境的麻烦。
    • 你是对的,它会起作用,但是我现在不确定你认为什么未指定的编译器行为在起作用。
    • 啊,我只是在引用 Andreas 对 Map javadoc 的引用:“如果对象的值以影响等于比较的方式更改,而对象是地图中的一个键。”
    猜你喜欢
    • 2018-02-12
    • 2011-08-14
    • 2011-10-21
    • 1970-01-01
    • 1970-01-01
    • 2013-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多