2

我正在尝试迭代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 操作从映射中移除相应的映射。它不支持 add 或 addAll 操作。

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

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

initial
10
another
10

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

4

5 回答 5

5

您正在修改key,而不是map。无法Map<K,V>检测到您更改了其中的对象。要使地图“看到”您需要调用的remove(originalKey)更改,更改键,然后调用put(modifiedKey,object)

修改地图将调用clearputputAllremove

于 2012-07-05T15:32:38.300 回答
4

根据java.util.Map javadoc

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

换句话说,如果您更改键对象的方式会影响键在映射中的索引方式,则映射不需要正常工作。

于 2012-07-05T18:19:41.967 回答
0

我相信i.name = "another"正在改变SubClass i对象的哈希码,这就是你取回一个null值的原因。如果不使用的hashcode功能,代码将起作用。Subclassname

所以当你打电话时,anotherMap.put(i, map.get(i));你真的在​​打电话anotherMap.put(i, null);

的目的HashMap是在 O(1) 时间内执行查找。这就是为什么它从哈希码中获取SubClass i而不更新它的原因。您的建议需要一个 lazy HashMap,但这会花费 O(n) 时间并破坏目的。

于 2012-07-05T15:33:13.110 回答
0

尝试类似:

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

    i.name="another";

    anotherMap.put(i, old);
}
于 2012-07-05T15:33:42.520 回答
-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());
}

这将工作:)

于 2012-07-05T15:44:10.583 回答