HashMap keySet更改未反映在map中

时间:2012-07-05 15:25:47

标签: java hashmap

我正在尝试迭代HashMap并将一些元素重写到另一个地图,但我遇到了以下问题:

@Test
public void test() {
    Map<SubClass, String> map = new HashMap<SubClass,String>();
    Map<SubClass, String> anotherMap = new HashMap<SubClass,String>();
    map.put(new SubClass(), "10");

    for(SubClass i : map.keySet()) {
        System.out.println(i); // initial (because toString is implemented)
        System.out.println(map.get(i)); // 10
        // here it's ok...

        i.name="another";

        System.out.println(i); // another
        System.out.println(map.get(i)); // null!
        // but here it occurs that  map.get(i) returns null!

        anotherMap.put(i, map.get(i));
    }
    for(SubClass i : anotherMap.keySet()) {
        System.out.println(i); // another
        System.out.println(map.get(i)); // null!
    }
}
// SubClass has String name; and hashCode and equals implemented

根据javadoc:

  

java.util.Map.keySet()

     

返回此地图中包含的键的Set视图。该集由地图支持,因此更改为        地图反映在集合中,反之亦然。如果在对集合进行迭代时修改了映射        进度(通过迭代器自己的删除操作除外),迭代的结果是        未定义。该集支持元素删除,从地图中删除相应的映射,        通过Iterator.remove,Set.remove,removeAll,retainAll和clear操作。它不支持        添加或添加所有操作。

它说“地图的变化反映在集合中,反之亦然”。那么为什么它以这种方式表现最重要:如何克服它以使两个映射仅包含修改的键和非空值?

更新: 我的朋友在java 1.5.0.19上做了这个测试(我有1.7.0_03,同样的情况发生在1.5.0_21)并得到了正确的输出:

initial
10
another
10

UPDATE2: 哦,他没有实现hashCode / equals,所以第一次更新是无关紧要的

5 个答案:

答案 0 :(得分:5)

您正在修改,而不是地图Map<K,V>无法检测到您已更改其中的对象。制作地图&#34;看&#34;您需要更改remove(originalKey),更改密钥,然后拨打put(modifiedKey,object)

修改地图将调用clearputputAllremove

答案 1 :(得分:4)

根据java.util.Map javadoc

  

注意:如果将可变对象用作映射键,则必须非常小心。如果在对象是地图中的键时,以影响等于比较的方式更改对象的值,则不指定映射的行为。

换句话说,如果以影响键在地图中索引方式的方式更改关键对象,则不需要地图正常工作。

答案 2 :(得分:0)

我相信i.name = "another"正在更改SubClass i对象的哈希码,这就是您获得null值的原因。如果hashcode的{​​{1}}函数未使用Subclass,则代码将有效。

所以当你致电name时,你真的在​​呼唤anotherMap.put(i, map.get(i));

anotherMap.put(i, null);的目的是在O(1)时间内执行查找。这就是它从HashMap获取哈希码并且不更新它的原因。你的建议需要一个懒惰的SubClass i,但这需要花费O(n)时间并且无法达到目的。

答案 3 :(得分:0)

尝试使用以下内容:

for(SubClass i : map.keySet()) {
    Object old = map.get(i);

    i.name="another";

    anotherMap.put(i, old);
}

答案 4 :(得分:-1)

我正在回答自己,因为我的朋友比以前任何人都有更好的解决方案:

for (Map.Entry<SubClass, String> entry: map.entrySet()) {
    System.out.println(entry.getKey().name);
    System.out.println(entry.getValue());

    entry.getKey().name = "another";

    System.out.println(entry.getKey().name);
    System.out.println(entry.getValue());
}

这将有效:)