我正在尝试迭代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,所以第一次更新是无关紧要的
答案 0 :(得分:5)
您正在修改键,而不是地图。 Map<K,V>
无法检测到您已更改其中的对象。制作地图&#34;看&#34;您需要更改remove(originalKey)
,更改密钥,然后拨打put(modifiedKey,object)
。
修改地图将调用clear
,put
,putAll
或remove
。
答案 1 :(得分:4)
注意:如果将可变对象用作映射键,则必须非常小心。如果在对象是地图中的键时,以影响等于比较的方式更改对象的值,则不指定映射的行为。
换句话说,如果以影响键在地图中索引方式的方式更改关键对象,则不需要地图正常工作。
答案 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());
}
这将有效:)