2011-03-13 34 views
0

有人可以解釋爲什麼HashMap的行爲就像它在這個例子中的樣子:
簡單的測試,檢查密鑰的散列表。一旦在構造函數中並且一次在ListDataListener的intervallAdded方法中。Java HashMap無法從ListDataListener事件中找到鍵

import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 

import javax.swing.event.ListDataEvent; 
import javax.swing.event.ListDataListener; 

import com.jgoodies.common.collect.ArrayListModel; 

public class Test1 { 

    private final Listener listener = new Listener(); 
    private final Map<List<?>, Object> parentByCollection = new HashMap<List<?>, Object>(); 

    public Test1(){ 
    ArrayListModel<Object> list = new ArrayListModel<Object>(); 

    list.addListDataListener(listener); 

    parentByCollection.put(list, new Integer(10)); 

    // Test containsKey locally 
    System.out.println("Item exists (locally):" + parentByCollection.containsKey(list)); 

    // Test containsKey via ListDataListener 
    list.add(new Integer(20)); 
    } 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
    new Test1(); 
    } 

    public class Listener implements ListDataListener{ 

    @Override 
    public void intervalAdded(ListDataEvent e) { 
     List<?> itemSource = (List<?>)e.getSource(); 

     System.out.println("Item exists (listener):" + parentByCollection.containsKey(itemSource));  
    } 

    @Override 
    public void intervalRemoved(ListDataEvent e) { 
    } 

    @Override 
    public void contentsChanged(ListDataEvent e) { 
    } 
    } 
} 

爲什麼在使用containsKey時hashmap從事件返回false,但從構造函數返回true? 在這裏有一些我不知道的java-泛型「magic」嗎?

編輯:

剛剛發現的ArrayList的(這ArrayListModel擴展)hashCode方法從它的所有元素組裝的哈希碼。這意味着hashCode隨着列表中的項目而改變。 因此,將ArrayList存儲在HashMap中並不是一個好主意。

我該如何解決這個問題?將集合存儲在持有者/容器對象中?

+2

請提供'com.jgoodies.common.collect.ArrayListModel'的hashCode()方法實現。 – 2011-03-13 10:23:15

+1

你可以在這裏http://www.jgoodies.com/downloads/libraries.html ArrayListModel找貨源擴展ArrayList和沒有重載hashCode,所以我想ArrayList的的hashCode是所使用的一個。但我不明白這是如何相關的,第一次調用containsKey返回true。 – Marcus 2011-03-13 10:28:04

回答

2

我知道你現在明白了這個問題,但這裏是爲其他人的解釋:

HashMap中使用的關鍵,在這種情況下是列表的哈希碼的哈希碼。

縱觀名單的hashCode方法的javadoc的解釋,該清單的哈希碼取決於所含的元素,以尊重散列碼與平等之間的合同。

由於合同的任何後續修改導致平等變化也將導致哈希碼更改,因此哈希映射將無法檢索初始列表。

在這種情況下的解決方案是使用一個參考,當元素被添加或從列表中刪除它不會改變。但是列表的一個克隆(與它相等)將不起作用!

0

的問題是很明顯的,當我通過看來源。在地圖存儲集合的解決方法是不使用HashMap的,而是使用基於諸如Apache公地ReferenceIdentityMap或java.util.IdentityHashMap中引用的地圖。

+0

或重新實現hashCode方法。 – 2011-03-13 11:02:16

+0

當然,這也是一個解決方案。但它是一個更簡潔的解決方案,可以使用一個適用於鍵的引用相等的Map。 – Marcus 2011-03-13 11:10:20

+0

Mush更清潔的解決方案是不使用列表作爲地圖的鍵) – 2011-03-13 11:16:04