在调用一个Iterator.remove() HashSet时,我遇到了问题。
我有一套有时间戳的东西。在向集合添加新项之前,我循环遍历该集合,标识该数据对象的旧版本并删除它(在添加新对象之前)。时间戳包含在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()默认失败(无一例外)。我已经核实了
等于之后不会更改,hashCode()方法使用@重写来确保它们是正确的方法。单元测试验证这些工作。如果我只使用一个for语句和一个
我想我一定是错过了一些基本的东西,但在这方面花了大量的时间之后,我和我的同事感到很困惑。有什么建议要检查吗?
编辑:
有一些问题-- 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的哈希代码就会被更改。
非常微妙--我看了这么多次,并没有注意到它的不可变性。
发布于 2008-11-01 23:27:26
我对这个仍然很好奇,并写了以下测试:
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;
public class HashCodeTest {
private int hashCode = 0;
@Override public int hashCode() {
return hashCode ++;
}
public static void main(String[] args) {
Set<HashCodeTest> set = new HashSet<HashCodeTest>();
set.add(new HashCodeTest());
System.out.println(set.size());
for (Iterator<HashCodeTest> iter = set.iterator();
iter.hasNext();) {
iter.next();
iter.remove();
}
System.out.println(set.size());
}
}其结果是:
1
1如果对象的hashCode()值在添加到HashSet后发生了更改,则它似乎使对象不可移动。
我不确定这是否是你遇到的问题,但如果你决定重新审视这个问题,这是值得研究的。
发布于 2008-11-01 05:01:56
在幕后,HashSet使用HashMap,在调用HashSet.remove(Object)或Iterator.remove()时调用HashMap.removeEntryForKey(Object)。该方法同时使用hashCode()和equals()来验证它是否正在从集合中移除适当的对象。
如果Iterator.remove()和HashSet.remove(对象)都不能工作,那么equals()或hashCode()方法肯定有问题。发布这些代码将有助于诊断您的问题。
发布于 2008-11-01 03:37:23
你确定DataResult是不可变的吗?时间戳的类型是什么?如果它是一个java.util.Date,那么在初始化DataResult时,您是否正在复制它?请记住,java.util.Date是可变的。
例如:
Date timestamp = new Date();
DataResult d = new DataResult(timestamp);
System.out.println(d.getTimestamp());
timestamp.setTime(System.currentTimeMillis());
System.out.println(d.getTimestamp());会印两个不同的时间。
如果您可以发布一些源代码,这也会有所帮助。
https://stackoverflow.com/questions/254441
复制相似问题