2013-07-05 70 views
7

直接從this Java文檔:將containsig本身映射爲一個值;

這一禁令的一種特殊情況是,這是不允許的 地圖以自身作爲一個鍵。雖然允許將一個包含 的地圖作爲值包含在內,但建議您格外小心:在這樣的地圖上,equals和 hashCode方法不再被很好地定義。

爲什麼哈希碼,等於不再得到很好的這樣的地圖上標示?

在此先感謝。

+2

如果我沒記錯的話,equals方法會檢查映射的內容是平等的。並且這是使用內容的等號方法即地圖本身來完成的。我很確定我們最終會出現StackOverflowError –

+0

可能是地圖等於函數的樣子嗎?也許它會導致無限循環?只是一個想法 – Kevin

+0

@MarcoForberg如果我沒有記錯,最好的做法是檢查你正在比較的對象是否真的是你自己,如果是的話,立即返回true。 –

回答

2

從Java文檔中的段落的完整報價:

注意:如果使用可變對象作爲map的key 很大,一定要小心。如果對象的值以影響等於比較的方式更改,而對象是地圖中的關鍵字,則不會指定地圖的行爲。這種禁令的一個特例是,不允許地圖將自身作爲關鍵字。雖然地圖可以包含自身作爲值是允許的,但建議您非常小心:equals和hashCode方法在這樣的地圖上不再被很好地定義。

AbstractMap.hashCode()方法使用映射中鍵值對的哈希碼來計算哈希碼。因此,每次修改地圖時,從該方法生成的哈希碼都會更改。

散列碼用於計算存儲桶以放置新條目。如果地圖本身被用作關鍵字,則每次更新/刪除/修改新條目時,計算出的存儲桶都會有所不同。因此,將地圖作爲關鍵字的未來查找很可能會失敗,因爲根據哈希代碼計算不同的存儲桶。未來的投入可能無法檢測到密鑰已經存在於地圖中,然後允許具有相同密鑰(但在不同桶中)的多個條目

1

如果相同的鍵映射相同的值,則兩個映射相等。 (在一些實現中。)因此爲了檢查平等,應該檢查每個成員的平等。

因此,如果地圖包含自身,則會得到無限次的等式檢查遞歸。

散列函數也是如此,因爲這些散列函數可以根據地圖中元素的散列值進行計算。

實施例:

Map<Int, Object> ma; 
Map<Int, Object> mb; 
Map<Int, Object> mc; 

ma.put(1, ma); 
ma.put(2, mb); 
mc.put(1, ma); 
mc.put(2, mb); 

作爲人,我們可以看到mamc是自定義相等。計算機會在兩張地圖上看到兩張地圖(空白地圖),這很好。它會在mc和ma的另一張地圖上看到1張地圖。它會檢查這些地圖是否相同。爲了確定這一點,它再次檢查1的兩個值是否相等。然後再次。

請注意,這不是所有實現的情況。有些實現可能會檢查內存中對象被保存的位置是否相等,但是每個遞歸檢查都會無限循環。

5

其用於通過最Map實現有關部分形式AbstractMap.equals:

  Iterator<Entry<K,V>> i = entrySet().iterator(); 
      while (i.hasNext()) { 
       Entry<K,V> e = i.next(); 
       K key = e.getKey(); 
       V value = e.getValue(); 
       if (value == null) { 
        if (!(m.get(key)==null && m.containsKey(key))) 
         return false; 
       } else { 
        if (!value.equals(m.get(key))) // would call equals on itself. 
         return false; 
       } 
      } 

添加在地圖上以值將導致無限循環。

+1

equals()方法的第一條語句是** if(o == this)return true; **我認爲這會阻止無限循環,因爲它會立即返回並永遠不會執行您突出顯示的代碼。 –

+0

該死的你是對的。答案需要不加標記。也許這是因爲它是如此實現依賴,他們沒有定義它不推薦它。 – ssindelar

+0

好吧,您可以通過創建兩個地圖來創建問題,將一個地圖放入另一個地圖,然後在另一個地圖上用另一個地圖作爲參數調用equals。或者您只需將一張地圖放入自身並調用hashcode() –

0

試圖解釋它:

equals方法將遍歷兩個地圖和調用地圖的每個鍵和值的equals方法。所以,如果一個地圖包含它自己,你會一直不停地調用equals方法。

散列碼發生同樣的事情。

來源:類的源代碼AbstractMap