对于直接从集合中提取的对象,为什么“.contains”会返回false?

时间:2012-05-11 16:45:02

标签: java collections ormlite

private Collection<Episode> episodes = new ArrayList<Episode>();

public void checkEpisodes(String string) {
    for(Episode episode : this.episodes){
        System.out.println(string + this.episodes.contains(episode));
    }
}

为什么上面的代码会打印错误?

我正在使用一个集合,因为这是ormlite允许的。我认为这个问题可能是由ormlite引起的,因为一个非常相似的类有一个相同的方法可以打印出来。

我要做的是修改返回的对象:

public Episode findEpisode(int num) {
    checkEpisodes("Find: ");
    for(Episode episode : this.episodes) {
        if(episode.getNumber()==num) {
            return episode;
        }
    }
    return null;
}

但不保存对该对象的修改。我假设因为它不包含在Collection中。

我的解决方案,但有效但不理想:

public void modifyEpisode(Episode episode) {
    checkEpisodes("Modify: ");
    for (Iterator<?> it = this.episodes.iterator(); it.hasNext();) {
        if (((Episode) it.next()).getNumber()==episode.getNumber()) {
            it.remove();
            addEpisode(episode.getNumber(), episode.getLink(), episode.getLinkLabel());
        }
    }
}

如果您需要查看更多我的代码,请问,项目有点涉及,但它是在sourceforge上托管的,我可以在必要时发布链接。

2 个答案:

答案 0 :(得分:10)

for(Episode episode : this.episodes) {
    System.out.println(string + this.episodes.contains(episode));
}
  

为什么上面的代码会打印错误?

在一般意义上,使用标准集合,我可以看到equals()方法中是否存在错误的唯一方法。对于大多数集合,contains()遍历集合并使用equals()Object.equals()可以正常工作,因为您可能已经覆盖了默认的equals方法,并且存在错误。

这也是ORMLite的作用。如果该集合渴望,则会在内部contains()上为ArrayList的项目调用equals()。如果集合是 lazy ,那么它会在整个表中使用迭代器,并再次使用equals()查看是否匹配。

修改

啊哈。您声明尚未覆盖equals()方法。

要记住的一件重要事情(就ORMLite而言)是这是一个 lazy 集合,内存中没有对象的存储。当您在延迟集合中进行迭代时,您将从数据库中获取Episode对象的实例。然后,当您调用contains()时,它会再次重复通过集合从数据库创建新的Episode对象。它会尝试比较两个对象,但如果您使用Object.equals(),它们永远不会相等,因为不是相同的对象引用。

必须才能覆盖equals()方法,以使contains()能够用于延迟收藏。

此外,虽然您的帖子可能是代码的简化,但您可以考虑将延迟集合拉入数组,然后迭代它。你不能在数组上做contains()但是如果你需要搜索数组,你就不会在数据库中进行两次迭代。

修改

因此解决方案变得更加复杂。事实证明,OP有一个Show对象,有一组急切的Season个对象,每个对象都有另一个急切的Episode个对象集合。默认情况下,每当ORMLite具有嵌套的eager集合时,由于性能原因,内部集合将变为 lazy 集合。遗憾的是,4.40版本没有详细记录。您可以通过在maxEagerLevel = 2对象的集合中设置Show(或更多)来更改此设置。请参阅documentation on maxEagerLevel

@ForeignCollectionField(eager = false, maxEagerLevel = 2)
ForeignCollection<Season> seasons;

答案 1 :(得分:0)

现在,ormlite是对象关系映射器,它管理对象及其修改状态。它还提供了保存修改过的剧集的方法;你提到的一点。但是关于错误:你应该根据价值创建一个等于。在ORM和类似的托管库中,序列化可能会为同一个对象提供不同的/ proxies实例,并且可能会通过字节代码操作(AOP)拦截对方法的访问。

modification的一个例子:

for (Order order : account.orders()) {
    // if we are changing some field in the order
    order.setAmount(123);
    // then we need to update it in the database
    account.orders.update(order);
}