12

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

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
4

2 回答 2

17

第二个(只是使用HashSet)只是一个巧合。从JavaDocs

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

第三个 ( LinkedHashSet) 被设计成这样:

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

于 2012-02-19T00:55:38.380 回答
5

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

例如,如果您使用new HashSet<>(4)which 将存储桶的初始数量设置为 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]

如果你的值 >= 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]
于 2016-01-26T00:08:24.797 回答