簡體   English   中英

為什么ArrayList不作為HashMap的關鍵工作?

[英]why doesn't ArrayList as key in HashMap work?

我試圖使用ArrayList作為HashMap的鍵,但是如果我在將列表設置為鍵后將值添加到列表中,則地圖將不再識別列表。 我已經為我的問題找到了一個解決方案,但這是一種丑陋的方式,這里有一些問題的示例代碼:

HashMap<Object,String> hm = new HashMap<Object,String>();

List<String> l = new ArrayList<String>();
hm.put(l, "stuff");
l.add("test");//add item after adding the list to the hashmap

System.out.println(hm.get(l));

這將返回文本“null”而

HashMap<Object,String> hm = new HashMap<Object,String>();

List<String> l = new ArrayList<String>();
l.add("test"); //add item before adding the list to the hashmap
hm.put(l, "stuff");

System.out.println(hm.get(l));

工作正常並返回“東西”

有誰知道為什么會這樣?

簡短:因為密鑰必須是不可變的以使哈希映射起作用(至少它們的身份必須是不可變的)而列表不是。

Long:當您向地圖添加密鑰時,其hashCode()方法用於確定條目的存儲區。 在該桶內部, equals()用於檢查該密鑰是否已存在於那里。 查找也是如此。

現在ArrayList執行一個深度equals()hashCode()所以如果你使用它作為鍵更改列表你將最終在一個不同的存儲桶或equals()的不同結果,並且地圖很可能找不到它。

編輯

AbstractList hashCode()實現( ArrayList擴展):

public int hashCode() {
    int hashCode = 1;
    for (E e : this)
        hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
    return hashCode;
}

正如您所看到的:如果列表為空,則哈希碼將為1,否則哈希碼將是其他內容(在您的情況下為31 * "test".hashCode() )。 因此,你可能最終會看到一個會失敗的不同桶。

編輯2

澄清“ equals()不同結果”:當然,如果用作鍵的列表和用於查找的列表包含相同順序的相同元素,則equals()應該返回true。 但是如果在將其用作關鍵字后更改該列表,則可能會在不同的情況下結束:

  • 雖然hashCode返回一個不同的值,但它可能會映射到同一個存儲桶(在最壞的情況下,只能想到地圖中的一個存儲桶)。 在這種情況下,你最終會在列表中找到兩個相同的鍵,盡管它們之前並不相同。
  • 您可能不知道列表的更改,因此即使您認為自己也可能不會使用相同的列表進行查找。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM