2012-02-19 99 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]