直接從this Java文檔:將containsig本身映射爲一個值;
這一禁令的一種特殊情況是,這是不允許的 地圖以自身作爲一個鍵。雖然允許將一個包含 的地圖作爲值包含在內,但建議您格外小心:在這樣的地圖上,equals和 hashCode方法不再被很好地定義。
爲什麼哈希碼,等於不再得到很好的這樣的地圖上標示?
在此先感謝。
直接從this Java文檔:將containsig本身映射爲一個值;
這一禁令的一種特殊情況是,這是不允許的 地圖以自身作爲一個鍵。雖然允許將一個包含 的地圖作爲值包含在內,但建議您格外小心:在這樣的地圖上,equals和 hashCode方法不再被很好地定義。
爲什麼哈希碼,等於不再得到很好的這樣的地圖上標示?
在此先感謝。
從Java文檔中的段落的完整報價:
注意:如果使用可變對象作爲map的key 很大,一定要小心。如果對象的值以影響等於比較的方式更改,而對象是地圖中的關鍵字,則不會指定地圖的行爲。這種禁令的一個特例是,不允許地圖將自身作爲關鍵字。雖然地圖可以包含自身作爲值是允許的,但建議您非常小心:equals和hashCode方法在這樣的地圖上不再被很好地定義。
AbstractMap.hashCode()方法使用映射中鍵值對的哈希碼來計算哈希碼。因此,每次修改地圖時,從該方法生成的哈希碼都會更改。
散列碼用於計算存儲桶以放置新條目。如果地圖本身被用作關鍵字,則每次更新/刪除/修改新條目時,計算出的存儲桶都會有所不同。因此,將地圖作爲關鍵字的未來查找很可能會失敗,因爲根據哈希代碼計算不同的存儲桶。未來的投入可能無法檢測到密鑰已經存在於地圖中,然後允許具有相同密鑰(但在不同桶中)的多個條目
如果相同的鍵映射相同的值,則兩個映射相等。 (在一些實現中。)因此爲了檢查平等,應該檢查每個成員的平等。
因此,如果地圖包含自身,則會得到無限次的等式檢查遞歸。
散列函數也是如此,因爲這些散列函數可以根據地圖中元素的散列值進行計算。
實施例:
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);
作爲人,我們可以看到ma
和mc
是自定義相等。計算機會在兩張地圖上看到兩張地圖(空白地圖),這很好。它會在mc和ma的另一張地圖上看到1張地圖。它會檢查這些地圖是否相同。爲了確定這一點,它再次檢查1的兩個值是否相等。然後再次。
請注意,這不是所有實現的情況。有些實現可能會檢查內存中對象被保存的位置是否相等,但是每個遞歸檢查都會無限循環。
其用於通過最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;
}
}
添加在地圖上以值將導致無限循環。
equals()方法的第一條語句是** if(o == this)return true; **我認爲這會阻止無限循環,因爲它會立即返回並永遠不會執行您突出顯示的代碼。 –
該死的你是對的。答案需要不加標記。也許這是因爲它是如此實現依賴,他們沒有定義它不推薦它。 – ssindelar
好吧,您可以通過創建兩個地圖來創建問題,將一個地圖放入另一個地圖,然後在另一個地圖上用另一個地圖作爲參數調用equals。或者您只需將一張地圖放入自身並調用hashcode() –
試圖解釋它:
equals方法將遍歷兩個地圖和調用地圖的每個鍵和值的equals方法。所以,如果一個地圖包含它自己,你會一直不停地調用equals方法。
散列碼發生同樣的事情。
來源:類的源代碼AbstractMap
如果我沒記錯的話,equals方法會檢查映射的內容是平等的。並且這是使用內容的等號方法即地圖本身來完成的。我很確定我們最終會出現StackOverflowError –
可能是地圖等於函數的樣子嗎?也許它會導致無限循環?只是一個想法 – Kevin
@MarcoForberg如果我沒有記錯,最好的做法是檢查你正在比較的對象是否真的是你自己,如果是的話,立即返回true。 –