Java HashSet中元素的排序

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

Integer[] j = new Integer[]{3,4,5,6,7,8,9}; LinkedHashSet i = new LinkedHashSet(); Collections.addAll(i,j); System.out.println(i); HashSet hi = new HashSet(i); System.out.println(hi); LinkedHashSet o = new LinkedHashSet(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 

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

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

第三个( LinkedHashSet ) 设计如下:

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

@Behrang的答案很好但是更具体一点, HashSetLinkedHashSet顺序相同的唯一原因是integer.hashCode()碰巧是整数值本身,所以数字恰好按顺序排列HashSet内部存储。 这是高度具体的实现,正如@Behrang所说,真的很巧合。

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

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

如果你坚持使用> = 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]