有人可以解释为什么HashMap的行为与此示例中的行为相同:
检查密钥的哈希映射的简单测试。一旦进入构造函数,一次进入ListDataListener intervallAdded方法。
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) {
}
}
}
为什么hashmap从事件返回false,但在使用containsKey时从构造函数返回true? 有一些java-generics“魔法”我不知道在这里?
编辑:
刚刚发现ArrayList(ArrayListModel扩展)hashCode方法从其所有元素组装其哈希码。这意味着hashCode随列表中的项目而变化。 因此,将一个ArrayList存储在HashMap中并不是一个好主意。
我该如何解决这个问题?将集合存储在持有者/容器对象中?
答案 0 :(得分:2)
我知道你现在理解这个问题,但这是其他人的解释:
HashMap使用密钥的哈希码,在这种情况下是List的哈希码。
查看List的hashcode方法的javadoc解释了列表的哈希码取决于包含的元素,以便尊重哈希码和相等之间的契约。
由于合同,对列表的任何后续修改导致相等更改也将导致哈希码更改,因此Hashmap将无法检索初始列表。
这种情况下的解决方案是使用引用,在列表中添加或删除元素时不会更改。但是列表的克隆(一个等于它的列表)将不起作用!
答案 1 :(得分:0)
当我浏览消息来源时,问题非常明显。在地图中存储集合的解决方案是不使用HashMap,而是使用基于apache commons ReferenceIdentityMap或java.util.IdentityHashMap等引用的地图。