2012-02-19 107 views
1

为什么在第二和第三组中保持秩序:排序在Java中的HashSet的元素

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 
+0

http://stackoverflow.com/a/2704640/1048330 – tenorsax 2012-02-19 00:56:24

+0

*一般来说*,地图(或设置)使用散列实现具有良好定义的没有秩序。 (尽管* some *实现,例如LinkedHashSet,有一个as-added命令;请参阅[class-level]文档以获得保证(如果有的话)。HashSet和LinkedHashSet文档中讨论了该行为。) – 2012-02-19 01:02:06

+1

Behrang在说这是巧合。主要从整数哈希码保持顺序的事实。尝试向哈希集添加更多的数字以及更大的数字,并查看是否保留了元素的顺序。 – 2012-02-19 01:15:32

回答

8

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

该类实现Set接口,由一个哈希表(实际上是一个HashMap实例)支持。它对集合的迭代次序没有任何保证; 特别是,它不能保证订单将随着时间的推移保持不变。这个类允许null元素。

第三个(LinkedHashSet)是designed是这样的:

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

2

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

例如,如果使用new HashSet<>(4)其设定桶的初始数目为(而不是16)4,那么你可能已经得到以下输出:

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] 

如果已经停留在值> = 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]