java - HashMap 删除不起作用

标签 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 函数时,保存在 HashMap 中的所有哈希返回相等。正在生成的哈希码实际上只是一个不同的 LinkedHashMap 的哈希码。这意味着 TicketItem 的 hashCode() 函数使用了 LinkedHashMap 的 hashCode() 函数。

最佳答案

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

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

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

但是,如果我们使用相同的 Item 引用运行 remove(),Android 的 HashMap 将再次在存储桶 4 中查找。但是此代码不执行身份 (==) 检查 - 它检查计算的 hashCode 和 equals()。但是由于计算的 hashCode 发生了变化(20 对 36),删除失败。

因此,总结一下:添加对象后 hashCode 发生了变化,新的 hash code 恰好映射到同一个 bucket。

(请注意,我自己发现这种桶碰撞不太可能发生,特别是考虑到该实现执行了一些神奇的位操作以防止糟糕的哈希算法。可能还有其他解释,但这是我根据发现发现的唯一合乎逻辑的解释所以远。)

关于java - HashMap 删除不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22584807/

相关文章:

java - 以大小受限的 block 将数据发送到数据库

java - HashMap/Hashtable 在 for 循环中不返回 int 作为键值

java - 糟糕的动态编程实现或 HashMap 慢?

java - 安装 Blackboard Auto Signon 构建 block

java - 替换 Clavier.lireDouble

java - 如果插件 jar 中的不同 jar 具有相同的类名,则访问类

java - 为什么我应该关心 Java 中捕获的异常?

java - Android:在没有可搜索 Activity 的情况下提供最近的搜索建议?

java - 在非 Activity 类中使​​用 Android Context

java - 计算 Java 中 Map 中某个键的出现次数