And*_*s S 4 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());
}
Run Code Online (Sandbox Code Playgroud)
我无法提供工作代码,因为它确实是一个巨大的项目。我已经将所有内容打印出来(如您在我的示例代码中所见),因此您知道 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
Run Code Online (Sandbox Code Playgroud)
如您所见,哈希码匹配,并且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());
}
Run Code Online (Sandbox Code Playgroud)
日志:
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
Run Code Online (Sandbox Code Playgroud)
更新 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;
}
Run Code Online (Sandbox Code Playgroud)
getValues() 返回具有任意(但相等!)值的 LinkedHashMap。
更新 3
equals 方法正确传递(没有问题)。但是,哈希码似乎正在发生变化。当我调用 remove 函数时,保存在哈希映射中的所有哈希都返回相等。生成的哈希码实际上只是不同的 LinkedHashMap 的哈希码。这意味着TicketItem 的hashCode() 函数使用LinkedHashMap 的hashCode() 函数。
假设将一个 Item 添加到大小为 16 的 HashMap。它的 hashCode=20。Android 的 HashMap 在存储桶 4 中创建一个条目,存储实际的哈希值 (20) 和对 Item 本身的引用。
现在假设修改了 Item,以便将 hashCode 更改为 36。
如果我们现在使用相同的 Item 引用运行 containsKey(),Android 的 HashMap 将在同一个桶中查找,4。在那里它根据身份 (==) 找到键。它是同一个对象,但此时它并不关心哈希码。
但是,如果我们使用相同的 Item 引用运行 remove(),Android 的 HashMap 将再次在存储桶 4 中查找。但是此代码不执行身份 (==) 检查 - 它检查计算的 hashCode 和 equals()。但由于计算出的 hashCode 已更改(20 对 36),删除失败。
因此,总结一下:自从添加对象以来,hashCode 发生了变化,并且新的散列代码恰好映射到同一个存储桶。
(请注意,我自己发现这种桶冲突不太可能发生,特别是考虑到该实现执行了一些魔术位操作以防止糟糕的散列算法。可能还有其他解释,但这是我根据迄今为止的调查结果认为合乎逻辑的唯一解释。)