这个HashSet如何产生排序输出?

Ash*_*win 6 java hashset

[1,2]即使hashset未排序,以下代码也会产生输出.

Set set = new HashSet();
set.add(new Integer(2));
set.add(new Integer(1));
System.out.println(set);
Run Code Online (Sandbox Code Playgroud)

这是为什么?

Kar*_*l S 10

编辑:从Java 8及更高版本开始,以下内容不再适用.这证明您不应该依赖未记录的Java行为.


此行为是由几个单独的原因引起的:

  • 整数哈希自己
  • 在Java中,HashMaps和HashSets由数组备份
  • 它们还使用较高位修改哈希值以修改较低位; 如果哈希值在0..15范围内,则不会被修改
  • 对象的去向取决于修改后的散列的低位
  • 当迭代地图或集合时,内部表格按顺序扫描

因此,如果向hashmap/hashset添加几个小的(<16)整数,则会发生以下情况:

  • 整数i有哈希码i
  • 因为它小于16,它的修改哈希也是 i
  • 它落在桶里没有. i
  • 在迭代时,桶会被顺序访问,所以如果你存储的所有内容都是小整数,它们将按升序检索

请注意,如果存储桶的初始数量太小,则整数可能会落在之后未编号的存储桶中:

HashSet<Integer> set = new HashSet<>(4);
set.add(5); set.add(3); set.add(1);
for(int i : set) {
  System.out.print(i);
}
Run Code Online (Sandbox Code Playgroud)

打印153.


ars*_*jii 5

根据HashSet文档不能保证任何订单概念,因此您在未来的Java更新中可以很好地改变.

不过,如果你想知道为什么Java的(截至目前)具体实施HashSet产生你所看到的结果是:这是因为该Integer值的1散列到的内部条目表的位置HashMap是来自之前的位置,它是2哈希(请注意,a HashSet实际上由HashMap具有任意值的a支持).这是有道理的,因为Integer对象的哈希码只是它的值.

实际上,即使添加更多数字(在一定范围内:条目表的大小默认为16),您也可以看到这一点:

Set<Integer> set = new HashSet<>();
set.add(2);
set.add(1);
set.add(4);
set.add(3);
set.add(0);
System.out.println(set);
Run Code Online (Sandbox Code Playgroud)
[0, 1, 2, 3, 4]

迭代在HashSet通过循环内部条目表,这意味着项目早在表格中是第一位的发生.