我有一个Hashmap,它有X个元素
我需要将此地图移动到另一个地图中
这就是我的代码看起来像
Map originMap = initialize();
Map destMap = new Hashmap ();
int originMapSize = originMap.size();
Set<Map.Entry<K, V>> entries = originMap.entrySet();
for (Map.Entry<K, Y> mapEntry : entries) {
K key = mapEntry.getKey();
V value = mapEntry.getValue();
destMap.put (key,value);
}
// Shouldnt this be equal to originMapSize ????
int destMapSize = destMap.size();
我观察的是 - originMapSize不等于destMapSize
似乎当我们将元素放在destMap中时,一些元素被覆盖
我们已经覆盖了hashCode和equals方法 - 这是一个可疑的实现 但是,如果originMap允许添加元素,为什么destinationMap不会添加新元素而是覆盖现有元素呢?
答案 0 :(得分:8)
如果equals
方法不对称,可能会发生这种情况。假设有两个键a和b,使得:
a.hashCode() == b.hashCode()
a.equals(b)
返回false b.equals(a)
返回true 然后假设HashMap
实现通过使用与新密钥相同的哈希码为每个现有密钥调用existingKey.equals(newKey)
来搜索现有密钥。
现在假设我们最初按照{a,b}的顺序添加它们。
第一个键(a
)显然没有任何问题。第二个密钥(b
)插入最终调用a.equals(b)
- 这是假的,因此我们得到两个密钥。
现在构建第二个HashMap
,我们最终可能会按顺序{b,a}获取条目。
这次我们首先添加b
,这很好......但是当我们插入第二个键(a
)时,我们最终调用b.equals(a)
,返回true,所以我们覆盖条目。
这可能不是正在发生的事情,但可以解释事情 - 并显示非对称equals
方法的危险。
编辑:这是一个简短但完整的程序,展示了这种情况。 (a
和b
的具体细节可能不一样,但不对称是。)
import java.util.*;
public class Test {
private final String name;
public Test(String name)
{
this.name = name;
}
public static void main(String[] args)
{
Map<Test, String> firstMap = new HashMap<Test, String>();
Test a = new Test("a");
Test b = new Test("b");
firstMap.put(b, "b");
firstMap.put(a, "a");
Map<Test, String> secondMap = new HashMap<Test, String>();
for (Map.Entry<Test, String> entry : firstMap.entrySet())
{
System.out.println("Adding " + entry.getKey().name);
secondMap.put(entry.getKey(), entry.getValue());
}
System.out.println(secondMap.size());
}
@Override public int hashCode()
{
return 0;
}
@Override public boolean equals(Object other)
{
return this.name.equals("b");
}
}
我机器上的输出:
Adding a
Adding b
1
你可能无法获得输出 - 这取决于:
equals
的方式(candidateKey.equals(newKey)
或反之亦然)在不同的跑步中它甚至可能有不同的作用。
答案 1 :(得分:0)
这些值应该相等,但问题是你在迭代不同的Map对象。
for (Map.Entry mapEntry : entries)
与
不同for (Map.Entry mapEntry : originMap)
答案 2 :(得分:0)
我怀疑添加到第一个hashmap的元素的顺序与添加到第二个hashmap的顺序不一样。这与粗略的hashCode方法相结合,导致重复项被添加到第一个。
尝试更改hashCode以始终返回相同的值,以查看问题是否消失。
答案 3 :(得分:0)
为什么不使用destMap.putAll(originMap)?
答案 4 :(得分:0)
Map有一个 putAll 方法。尝试这样的事情:
Map<String, String> destination = new HashMap<String, String>();
Map<String, String> original = new HashMap<String, String>();
destination.putAll(original);
答案 5 :(得分:0)
这取决于第一个HashMap的初始化方式。每次将对象添加到HashMap中时,一旦它通过75%的加载因子,它就会分配两倍的默认大小来容纳新值。地图通常具有默认大小= 16:当您通过75%的加载因子时,它会放大到32。