2015-10-30 48 views
1

我想修復一個代碼,我不能在這裏發佈,所以我有一個修剪版本在這裏。奇怪的行爲,而使用HashMap

我使用HashMap時出現不穩定的輸出。

HashMap<Integer, String> test= new HashMap<>(); 
test.put(1, "one"); 
test.put(2, "one"); 
test.put(3, "one"); 
test.put(4,"four"); 
test.put(5, "one"); 
test.put(6, "one"); 
test.put(10, "one"); 
test.put(19, "one");  
test.put(20, "Sixteen");  
System.out.println(test); 


HashMap<Integer, String> test3= new HashMap<>(200); 
test3.put(1, "one"); 
test3.put(2, "one"); 
test3.put(3, "one");  
test3.put(4,"four"); 
test3.put(5, "one"); 
test3.put(6, "one"); 
test3.put(10, "one"); 
test3.put(19, "one"); 
test3.put(20, "Sixteen"); 
System.out.println(test3); 

輸出

test --> {1=one, 19=one, 2=one, 3=one, 4=four, 20=Sixteen, 5=one, 6=one, 10=one} 
test3--> {1=one, 2=one, 3=one, 4=four, 5=one, 6=one, 10=one, 19=one, 20=Sixteen}---> My desired output. 

爲什麼結果不同,即使輸入值是相同的。這種排序有何不同,即存儲元素?

我無法使用第二種方法,因爲大小是動態的,它會根據應用程序不斷變化。我可以使用相同的TreeMap,併爲所有值獲得一致的輸出。

+0

你認爲在第一方法中的大小是靜態的? – SpringLearner

+0

HashMap不保證訂單 - 按照Java API –

+1

您*不能*使用HashMap並期望一致的排序。改爲使用LinkedHashMap或TreeMap。 –

回答

5

爲什麼的輸出是不同的,當尺寸不同 -

這一點,因爲在調用散列映射indexFor(散列,table.length)的put方法在內部調用。 Table.length是不同的,這意味着默認值是16,但第二種方式的大小是200.所以索引會不同。

請閱讀更多在這個article

我可以使用TreeMap中的相同,並且獲得所有值一致的輸出。

在樹形註冊就,鍵將被訂購,所以你會得到{1=one, 2=one, 3=one, 4=four, 5=one, 6=one, 10=one, 19=one, 20=Sixteen}

如果要檢索順序的方式插入其

+0

只是最後的一澄清,所以你的意思是說,對於HashMap的輸出結果會隨時間改變或者當我使用它在不同的機器。無論條件如何,TreeMap的輸出將保持不變。我不能使用LinkedHashMap,因爲當我使用它時,代碼在許多其他地方都會中斷。 – User27854

+0

@ user2900314我沒有說輸出會在不同的機器上改變加班時間。我只是做了聲明,爲什麼順序是不同的,當你默認構造函數hashmap – SpringLearner

1

這是因爲

新的HashMap <>()構造具有默認初始容量的空HashMap(16)

所以它往往要打印索引0 ---值> 15然後再從指數16→31考慮爲0 ---> 15。

+0

我同意這一點,但在上面的場景中,HashMap的大小不超過16個。我期待兩者都能得到相同的結果。 – User27854

+0

您在索引19和20因此19 ---> 3和20把值---> 4 – Shivam

+1

@ user2900314的intital容量是散列桶的數量,而不是字面上它可以包含的對象的數目。 –

0

Java docs條目的HashMap類,

此類不作任何保證,而地圖的順序;特別是,它不能保證訂單會隨着時間的推移保持不變。

1

HashMap不給保證您可以使用LinkedHashMap的作爲命令。如果您想根據您插入的訂單檢索地圖中的元素,則可以使用LinkedHashMap

+0

當我使用LinkedHashMap它失敗了許多其他地方。所以我不能使用它。 – User27854

+0

請您詳細說明它失敗的位置? 。按照你插入的方式來檢索,你應該使用'LinkedHashMap'。 – Truthira

+0

在我的實際代碼中,HashMap包含了一個xml的所有值。並且許多其他應用程序使用相同的代碼。當我作爲LinkedHashMap進行更改時,一個應用程序會被傳遞。但它在許多其他地方失敗了。爲什麼?我不知道,因爲我無法訪問這些代碼。 – User27854

2

使用HashMaps有一個概念稱爲加載因子。加載因子是在它自己調整大小之前hashmap可以達到多少。如果負載因子爲0.5(或50%),那麼當哈希映射達到50%的容量時,它將自行調整大小以爲更多元素騰出空間。

哈希映射通常具有小於100%的加載因子的原因是因爲存儲元素的方式。當你生成一個散列時,你使用了散列函數。您正在使用的哈希函數是默認值,並且基於正在存儲的對象的equals()方法,此時不重要。事情是,兩個元素可能以相同的散列結束,但不能保證是唯一的。當您嘗試使用相同的散列存儲兩個值時,它們最終會位於散列映射中的同一個「桶」中。這被稱爲碰撞。當你發生碰撞時,hashmap需要一個處理它的策略。

有時策略是「線性探測」。這意味着,如果一個元素髮生衝突,散列映射將遍歷接下來的幾個桶尋找一個空的桶。

有時候戰略「鏈接」的地方,如果一個元素碰撞,HashMap的將鏈表替換現有的元素,並把每一個列表中的碰撞的元素。

所有這些都意味着是,當元件在一個HashMap碰撞,它變得更慢插入和較慢的檢索的元素。所以爲了減少碰撞的機會,哈希映射根據負載因子調整自身大小。

在這一切之上,如其他人所說,沒有一個基本的HashMap訂購的保證。你需要使用像LinkedHashMap這樣的實現。

0

使用TreeMap,如果你想的鑰匙,自然排序

該地圖是根據其鍵的自然順序進行排序,或者通過 創建映射時提供一個比較具體取決於 使用構造函數。

Map<Integer, String> test= new TreeMap<>(); 
test.put(1, "one"); 
test.put(2, "one"); 
test.put(3, "one"); 
test.put(4,"four"); 
test.put(5, "one"); 
test.put(6, "one"); 
test.put(10, "one"); 
test.put(19, "one");  
test.put(20, "Sixteen");  
System.out.println(test); // Output : {1=one, 2=one, 3=one, 4=four, 5=one, 6=one, 10=one, 19=one, 20=Sixteen} 
0

HashMap中使用默認的初始容量(16)

{1 =一個,2 =一個,3 =一個,4 = 4,5 =一個,6 =一個,10 =一個}

{1 =一個,2 =一個,3 =一個,4 = 4,5 =一個,6 =一個,10 =一個}