【发布时间】:2008-10-31 18:25:44
【问题描述】:
我在 HashSet 上调用 Iterator.remove() 时遇到问题。
我有一组带有时间戳的对象。在将新项目添加到集合之前,我会遍历集合,识别该数据对象的旧版本并将其删除(在添加新对象之前)。时间戳包含在 hashCode 和 equals() 中,但不包含在 equalsData() 中。
for (Iterator<DataResult> i = allResults.iterator(); i.hasNext();)
{
DataResult oldData = i.next();
if (data.equalsData(oldData))
{
i.remove();
break;
}
}
allResults.add(data)
奇怪的是,对于集合中的某些项目, i.remove() 静默失败(没有例外)。我已经验证了
实际上调用了 i.remove() 行。我可以直接在Eclipse的断点处从调试器中调用它,它仍然无法改变Set的状态
DataResult 是一个不可变对象,因此它在最初添加到集合后不能更改。
equals 和 hashCode() 方法使用 @Override 来确保它们是正确的方法。单元测试验证这些工作。
如果我只使用 for 语句和 Set.remove,这也会失败。 (例如,遍历项目,在列表中找到项目,然后在循环后调用 Set.remove(oldData))。
我在 JDK 5 和 JDK 6 中测试过。
我认为我一定错过了一些基本的东西,但是在我和我的同事花了一些时间在这上面之后,我感到很困惑。有什么要检查的建议吗?
编辑:
有一些问题 - DataResult 真的是不可变的。是的。没有二传手。并且当检索到 Date 对象(它是一个可变对象)时,它是通过创建一个副本来完成的。
public Date getEntryTime()
{
return DateUtil.copyDate(entryTime);
}
public static Date copyDate(Date date)
{
return (date == null) ? null : new Date(date.getTime());
}
进一步编辑(稍后): 记录一下——DataResult 不是一成不变的!它引用了一个对象,该对象的哈希码在持久保存到数据库时会发生变化(我知道这是不好的做法)。事实证明,如果使用临时子对象创建 DataResult,并且子对象被持久化,则 DataResult 哈希码已更改。
非常微妙——我看了很多遍,并没有注意到缺乏不变性。
【问题讨论】:
-
两种可能。 1.你说DataResult是不可变的。假设值由构造函数设置并且没有设置方法是否安全? 2. 你的 equals 和 hashcode 没有像你预期的那样工作。你能把这两个的代码贴出来吗?
标签: java collections