Java HashSet中元素的排序

时间:2012-02-19 00:51:29

标签: java collections hashset linkedhashset

为什么第二组和第三组保留顺序:

Integer[] j = new Integer[]{3,4,5,6,7,8,9};
LinkedHashSet<Integer> i = new LinkedHashSet<Integer>();
Collections.addAll(i,j);
System.out.println(i); 

HashSet<Integer> hi = new HashSet<Integer>(i);
System.out.println(hi); 

LinkedHashSet<Integer> o = new LinkedHashSet<Integer>(hi);
System.out.println(o); 

这是我得到的输出:

3,4,5,6,7,8,9
3,4,5,6,7,8,9
3,4,5,6,7,8,9

2 个答案:

答案 0 :(得分:11)

第二个(仅使用HashSet)只是巧合。来自JavaDocs

  

此类实现Set接口,由哈希表(实际上是HashMap实例)支持。它不能保证集合的迭代顺序;特别是 ,它并不保证订单会随时间保持不变 。该类允许null元素。

第三个(LinkedHashSetdesigned就是这样:

  

Set接口的哈希表和链表实现,具有可预测的迭代顺序。此实现与HashSet的不同之处在于它维护了一个贯穿其所有条目的双向链表。此链接列表定义迭代排序,即元素插入集合(插入顺序)的顺序。请注意,如果将元素重新插入到集合中,则不会影响插入顺序。 (如果s.contains(e)在调用之前立即返回true,则调用s.add(e)时,将元素e重新插入到集合中。)

答案 1 :(得分:2)

@ Behrang的答案很好,但更具体一点,HashSet似乎与LinkedHashSet的顺序相同的唯一原因是integer.hashCode()恰好是整数值本身,因此数字恰好在HashSet内部存储中排序。这是高度特定的实现,正如@Behrang所说,真的很巧合。

例如,如果您使用new HashSet<>(4)将桶的初始数量设置为4(而不是16),那么您可能获得了以下输出:

HashSet<Integer> hi = new HashSet<Integer>(4);
...
[3, 4, 5, 6, 7, 8, 9]
[8, 9, 3, 4, 5, 6, 7]
[8, 9, 3, 4, 5, 6, 7]

如果你坚持使用值&gt; = 16,你可能会得到这样的结果:

Integer[] j = new Integer[] { 3, 4, 5, 6, 7, 8, 9, 16 };
...
[3, 4, 5, 6, 7, 8, 9, 16]
[16, 3, 4, 5, 6, 7, 8, 9]
[16, 3, 4, 5, 6, 7, 8, 9]