java中的映射问题
我有一个Hashmap,它有X个元素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 :
我需要将此地图移动到另一个地图
这就是我的代码的样子
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()
返回falsea.equals(b)
返回trueb.equals(a)
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<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);