HashMap删除无法正常工作

时间:2014-03-22 23:02:11

标签: java android hashmap

我已经阅读了有关此问题的所有答案,似乎没有任何效果。

这是我正在运行的代码:

HashMap<TicketItem, ArrayList<TicketItemModifier>> items = new HashMap<TicketItem, ArrayList<TicketItemModifier>>();    
        for (final TicketItem key : items.keySet()) {
            Log.i(key.equals(item));
            Log.i(key.hashCode() + " " + item.hashCode());
        }
        Log.i(items.size());
        Log.i("C: " + items.containsKey(item));
        items.remove(item);
        Log.i("C: " + items.containsKey(item));
        Log.i(items.size());
        for (final TicketItem key : items.keySet()) {
            Log.i(key.equals(item));
            Log.i(key.hashCode() + " " + item.hashCode());
        }

我无法提供工作代码,因为它确实是一个巨大的项目。我已经将所有内容打印出来(正如您在我的示例代码中看到的那样),因此您知道HashMap使用的值是正确的。

日志:

03-22 18:58:10.125: I/POSDoes(29790): true
03-22 18:58:10.125: I/POSDoes(29790): -823765791 -823765791
03-22 18:58:10.125: I/POSDoes(29790): false
03-22 18:58:10.125: I/POSDoes(29790): 1543283745 -823765791
03-22 18:58:10.125: I/POSDoes(29790): false
03-22 18:58:10.125: I/POSDoes(29790): 427224321 -823765791
03-22 18:58:10.125: I/POSDoes(29790): false
03-22 18:58:10.125: I/POSDoes(29790): -616760351 -823765791
03-22 18:58:10.125: I/POSDoes(29790): 4
03-22 18:58:10.125: I/POSDoes(29790): C: true
03-22 18:58:10.130: I/POSDoes(29790): C: true
03-22 18:58:10.130: I/POSDoes(29790): 4
03-22 18:58:10.130: I/POSDoes(29790): true
03-22 18:58:10.130: I/POSDoes(29790): -823765791 -823765791
03-22 18:58:10.130: I/POSDoes(29790): false
03-22 18:58:10.130: I/POSDoes(29790): 1543283745 -823765791
03-22 18:58:10.130: I/POSDoes(29790): false
03-22 18:58:10.130: I/POSDoes(29790): 427224321 -823765791
03-22 18:58:10.130: I/POSDoes(29790): false
03-22 18:58:10.130: I/POSDoes(29790): -616760351 -823765791

正如您所看到的,哈希码匹配,并且equals方法返回true,但是当打印出包含时,我在调用remove方法之前和之后都接收到true。为什么这不起作用?

更新

我打印出item.equals(key),结果相同。

for (final TicketItem key : items.keySet()) {
            Log.i(item.equals(key));
            Log.i(key.equals(item));
            Log.i(key.hashCode() + " " + item.hashCode());
        }
        Log.i(items.size());
        Log.i("C: " + items.containsKey(item));
        items.remove(item);
        Log.i("C: " + items.containsKey(item));
        Log.i(items.size());
        for (final TicketItem key : items.keySet()) {
            Log.i(item.equals(key));
            Log.i(key.equals(item));
            Log.i(key.hashCode() + " " + item.hashCode());
        }

日志:

03-22 19:09:14.360: I/POSDoes(30458): true
03-22 19:09:14.360: I/POSDoes(30458): true
03-22 19:09:14.360: I/POSDoes(30458): 1543283745 1543283745
03-22 19:09:14.365: I/POSDoes(30458): false
03-22 19:09:14.365: I/POSDoes(30458): false
03-22 19:09:14.365: I/POSDoes(30458): 427224321 1543283745
03-22 19:09:14.365: I/POSDoes(30458): false
03-22 19:09:14.365: I/POSDoes(30458): false
03-22 19:09:14.365: I/POSDoes(30458): -616760351 1543283745
03-22 19:09:14.365: I/POSDoes(30458): 3
03-22 19:09:14.365: I/POSDoes(30458): C: true
03-22 19:09:14.365: I/POSDoes(30458): C: true
03-22 19:09:14.365: I/POSDoes(30458): 3
03-22 19:09:14.365: I/POSDoes(30458): true
03-22 19:09:14.365: I/POSDoes(30458): true
03-22 19:09:14.365: I/POSDoes(30458): 1543283745 1543283745
03-22 19:09:14.365: I/POSDoes(30458): false
03-22 19:09:14.365: I/POSDoes(30458): false
03-22 19:09:14.365: I/POSDoes(30458): 427224321 1543283745
03-22 19:09:14.370: I/POSDoes(30458): false
03-22 19:09:14.370: I/POSDoes(30458): false
03-22 19:09:14.370: I/POSDoes(30458): -616760351 1543283745

更新2 这是equals()

的实现
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (!super.equals(obj))
        return false;
    if (this.getClass() != obj.getClass())
        return false;
    TicketItem other = (TicketItem) obj;
    if (!getValues().equals(other.getValues()))
        return false;
    return true;
}

getValues()返回一个具有任意(但相等!)值的LinkedHashMap。

更新3

equals方法正确传递(没有问题)。然而,似乎哈希码正在改变。当我调用remove函数时,哈希映射中保存的所有哈希都返回相等。生成的哈希码实际上只是一个不同的LinkedHashMap哈希码。意味着TicketItem的hashCode()函数使用LinkedHashMap的hashCode()函数。

1 个答案:

答案 0 :(得分:4)

假设将一个Item添加到大小为16的HashMap中。它的hashCode = 20。 Android的HashMap在桶4中创建一个条目,存储实际的散列(20)和对Item本身的引用。

现在假设修改了Item,以便hashCode更改为36。

如果我们现在使用相同的Item引用运行containsKey(),Android的HashMap将查看相同的存储桶,4。它会根据identity(==)找到密钥。它是相同的对象,但此时它并不关心哈希码。

但是如果我们使用相同的Item引用运行remove(),则Android的HashMap将再次查看存储桶4.但是此代码不执行标识(==)检查 - 它检查计算的hashCode和equals()。但由于计算出的hashCode已经改变(20比36),删除失败。

所以,总结一下:自添加对象以来,hashCode已经改变,新的哈希码恰好映射到同一个桶。

(请注意,我发现这个桶冲突不太可能,特别是考虑到实现会执行一些魔术位操作以防止不良的哈希算法。可能还有其他解释,但这是我发现的唯一一个基于结果的逻辑远。)