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

时间:2013-09-06 01:34:48

标签: java hashset

以下代码生成输出[1,2],即使hashset未排序。

Set set = new HashSet();
set.add(new Integer(2));
set.add(new Integer(1));
System.out.println(set);

为什么?

5 个答案:

答案 0 :(得分:10)

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


此行为是由几个不同原因引起的:

  • 整数哈希自己
  • 在Java中,HashMapHashSet由数组备份
  • 他们还使用较高位修改哈希值以修改较低位;如果散列在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);
}

打印153

答案 1 :(得分:5)

根据文档的HashSet并不保证任何订单概念,因此您所看到的内容在未来的Java更新中可能会发生很大变化。

但是,如果您想知道为什么Java(截至目前)HashSet的具体实现会产生您所看到的结果:这是因为值Integer的{​​{1}}哈希值1的内部条目表中位于之前 HashMap哈希值的位置的位置(注意2确实由{HashSet支持1}}具有任意值)。这是有道理的,因为HashMap对象的哈希码只是它的值。

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

Integer
[0, 1, 2, 3, 4]

通过迭代内部条目表来进行Set<Integer> set = new HashSet<>(); set.add(2); set.add(1); set.add(4); set.add(3); set.add(0); System.out.println(set); 的迭代,这意味着表格中较早的项目首先出现。

答案 2 :(得分:1)

HashSet是一个无序集合。它没有保证,也没有“订购”的概念。有关详细信息,请参阅此答案:What is the difference between Set and List?

如果您需要有序,有序的Set。

,可以考虑使用TreeSet

对于未排序的有序集合,还有LinkedHashSet

答案 3 :(得分:0)

java中的set不应该是有序列表。请改用ArrayList。另请参阅Java Collection API以获取进一步的参考。

答案 4 :(得分:0)

经过多次尝试和错误得出结论。这完全基于哈希顺序。这就是为什么我们称其为HASH set。散列基于输入的长度。尝试使用4个单位数字和4个两位数字。您将得到结果。