为什么我的Java HashMap
不起作用?我的对象具有.equals
相等意味着hashCode
相等的属性。
我可以假设在将对象添加到HashMap
后我正在修改对象的字段。
答案 0 :(得分:5)
您可以假设我在将对象添加到HashMap后修改了对象的字段。
这就是为什么。
注意:如果将可变对象用作映射键,则必须非常小心。 如果对象的值以影响等于比较的方式更改,而对象是地图中的关键字,则地图的行为未指定
"未指定"意味着"可能不起作用,所以当它不起作用时你不应该感到惊讶。
答案 1 :(得分:1)
如果您在之后改变(更改)对象,则将它们添加到HashMap
,您的对象将在错误的存储桶中。这是因为即使对象已更改,在更改发生后,对象也不会“重新”转换为(新的)正确的存储桶。
因此,像remove
这样的方法将无法找到您的对象,因为该对象位于过时的存储桶中。
真正推动这个家庭(对我而言)的是,当对象最初添加到HashMap
时,哈希值(int)与Entry一起存储。这意味着散列是一个相对静态的属性,很少(从未)更新。
可能的解决方法包括:
如果您遍历hashmap
中的每个条目并从这些条目创建新的HashMap
,它可能会有效。这在性能方面可能不好,但可能是最正确的事情。
请勿在{{1}}功能中包含正在更改的字段。虽然不是很好(利用未指定的编译器行为是最有风险的业务),但它往往会起作用,因为您只会遇到冲突,这只会影响性能,而不会影响正确性。您仍然需要在hashCode
方法中包含有问题的字段,否则您最终可能会删除错误的对象。
算法解决方案:找到一种在对象中存储不同数据的方法,该对象充当常量的关键字。例如,在我的应用程序中,我用整数字段跟踪对象的“年龄”。每次我在我的应用程序中达到一定的时间,我会增加所有键的年龄。如果某事超过50个单位的时间,那么我可以合理地抛出键值对。或者,我可以更改对象以存储对象的“出生时间”。也就是说,如果应用程序在创建对象时是1000个时间单位,那么我将存储数字1000.然后,为了确定对象的年龄,我可以将当前的“时间”与出生时间区分开来并扔掉如果差异是>对象50。