java中的映射问题

java中的映射问题,java,collections,hashmap,Java,Collections,Hashmap,我有一个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 :

我有一个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();
Map originMap=initialize();
Map destMap=newhashmap();
int originMapSize=originMap.size();
Set entries=originMap.entrySet();
对于(Map.Entry mapEntry:entries){
K key=mapEntry.getKey();
V value=mapEntry.getValue();
destMap.put(键、值);
}  
//这不应该等于原始地图大小吗????
int destMapSize=destMap.size();
我观察到的是-originMapSize不等于destMapSize

当我们把元素放到destMap中时,似乎有一些元素被覆盖了

我们已经过度使用了hashCode和equals方法,这是一个可疑的实现。

但是,如果originMap允许添加元素,那么destinationMap为什么不添加新元素并覆盖现有元素呢?

这些值应该相等,但问题是您正在迭代不同的Map对象

for (Map.Entry mapEntry : entries)
不一样

for (Map.Entry mapEntry : originMap)

我怀疑添加到第一个hashmap的元素的顺序与添加到第二个hashmap的顺序不同。这与sketchy hashCode方法相结合,导致将重复项添加到第一个


尝试更改hashCode以始终返回相同的值,以查看问题是否消失。

为什么不使用destMap.putAll(originMap)?

如果
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)
——这是false,因此我们得到两个键

现在构建第二个
HashMap
,我们可能最终得到{b,a}顺序的条目

这次我们先添加
b
,这很好。。。但是当我们插入第二个键(
a
)时,我们最终调用了
b.equals(a)
,它返回true,因此我们覆盖了条目

这可能不是正在发生的事情,但它可以解释事情——并显示不对称
equals
方法的危险

编辑:这里有一个简短但完整的程序来演示这种情况。(
a
b
的确切细节可能不尽相同,但不对称性不同。)

您可能无法通过这种方式获得输出-这取决于:

  • 调用
    equals
    的方式(
    candidateKey.equals(newKey)
    或反之亦然)
  • 从集合返回项的顺序
它甚至可能在不同的运行中起不同的作用。

Map有一个putAll方法。试着这样做:

    Map<String, String> destination = new HashMap<String, String>();
    Map<String, String> original = new HashMap<String, String>();

    destination.putAll(original);
Map destination=newhashmap();
Map original=新的HashMap();
目的地:putAll(原件);

这取决于第一个HashMap的初始化方式。此外,每次将对象添加到HashMap中时,一旦它通过75%的加载因子,它就会分配两倍的默认大小来容纳新值。贴图的默认大小通常为16:当您传递75%的加载因子时,它会放大到32。

初始化方法做什么,为什么
i++
在其中?您如何初始化“条目”正在for循环中迭代的变量?如果映射中已存在键,则它将覆盖以前的值。i++仅用于调试目的。现在删除它。@Varun:我的问题是-为什么第一个映射允许两个键同时存在,而第二个映射覆盖了它我很确定他指的是originMap.entrySet()。我不认为一个坏的
hashCode
实现会导致这种情况,但是一个糟糕的
等于
的实现当然可以-请看我的答案作为一个例子。你可能是对的,但由于hashCode只是一个性能调整,我会在调试类似问题时删除它。所谓“删除它”,你是指删除覆盖吗?这将完全改变行为,因为您将得到从
等于返回
true
但具有不同哈希代码的对象。你可以让它只返回0。。。但我认为这不是问题所在。是的,我只返回0。事实上,我会一直这样做,直到我发现性能问题。哇,真的吗?在大多数情况下很容易获得正确的哈希代码(只需遵循有效的Java)-为什么要将每个哈希映射查找都转换为O(n)操作?我完全赞成避免微观优化,但这是一个O(1)到O(n)的变化,所有这些都是为了不编写通常非常简单的方法。如何创建一个不对称的equals函数?嗯。我明白你的意思。使用Guava库中的多重映射是否会有帮助(如果我现在不想更改equals\hashcode)@RN:不确定。但是如果你有一个糟糕的equals/hashCode实现,修复它应该是你的首要任务——在你完成之前,你会看到奇怪的东西。刚刚验证过——equals方法是不对称的。谢谢,这很有帮助。同样的结果。第二张地图的大小不同。
Adding a
Adding b
1
    Map<String, String> destination = new HashMap<String, String>();
    Map<String, String> original = new HashMap<String, String>();

    destination.putAll(original);