我已经阅读了有关此问题的所有答案,似乎没有任何效果。
这是我正在运行的代码:
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()函数。
答案 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已经改变,新的哈希码恰好映射到同一个桶。
(请注意,我发现这个桶冲突不太可能,特别是考虑到实现会执行一些魔术位操作以防止不良的哈希算法。可能还有其他解释,但这是我发现的唯一一个基于结果的逻辑远。)