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

我有一些使用标准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的一些function,但无法将其跟踪到特定的代码行。

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中,这种随机化似乎不再存在。

从HashSet的文档 :

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

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

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

根据HashSet javadoc,

…不保证集合的迭代顺序

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