为什么HashSet的keySet中元素的顺序从运行变为运行?

时间:2014-07-16 03:37:54

标签: java

我有一些使用标准Java集合的代码:arrays,ArrayDeques,HashMaps,Lists,HashSets。 我的代码应该是确定性的:所有元素的哈希码,集合的初始内容等预计仅取决于输入数据。代码的最终输出是从某个HashMap的keySet()生成的。

我注意到生成的keySet中元素的顺序有时会随着运行而变化。这是什么意思?

  • 某些标准集合具有非确定性行为(例如,某些内部对象的哈希码是非确定性的)?
  • 我自己的代码实际上是非确定性的(例如,我忘了为某些类正确覆盖hashCode())?这可能意味着我某处有一个错误(测试尚未发现),这就是我担心的原因。
  • 别的什么?

这与Windows 7 x64上的JDK 1.7.0_60,x86完全一致。 据称,JDK 1.8.0_05不会发生这种情况(或很少发生)。 此外,在上述JDK之间切换时,生成的keySet中的元素顺序(以及处理数据项的整体顺序)也会发生变化。

我怀疑,这是HashSet的一些功能,但无法将其跟踪到特定的代码行。

UPD 1 我真的不需要确定性集合,我知道HashSet不提供任何保证。我只是想找到非确定性行为的原因。如果它在库代码中 - 很好。但如果它在我的代码中 - 我可能不得不修复它。因此问题。

UPD 2 当然,我在发布问题后立即找到答案。就在1.7的HashMap.java开头:

/**
 * A randomizing value associated with this instance that is applied to
 * hash code of keys to make hash collisions harder to find. If 0 then
 * alternative hashing is disabled.
 */
transient int hashSeed = 0;

在1.8中,这种随机化似乎不再存在。

3 个答案:

答案 0 :(得分:5)

来自documentation of HashSet

  

它不保证集合的迭代顺序;特别是,它不保证订单会随着时间的推移保持不变。

答案 1 :(得分:2)

如果你需要一个稳定的有序HashSet,那么你应该按照javadoc使用LinkedHashSet

  

Set接口的哈希表和链表实现,具有可预测的迭代顺序

根据HashSet javadoc,

  

...不保证集合

的迭代顺序

答案 2 :(得分:0)

只需在此处复制已包含在问题中的内容。快速浏览一下消息来源表明,在1.7中,HashMap确实具有非确定性行为,并且每个实例都使用一些随机值来对元素的散列进行种子处理。在1.8中,实现已经改变,随机化似乎不再存在。