compareTo和TreeSet的问题

时间:2011-05-08 20:04:12

标签: java treeset

我遇到了TreeSet从我正在处理的游戏中移除一个单元的问题。我正在制作塔防游戏,并且路径被分解成一组长度不同的块。块知道其中的单元和路径上的下一个块。当单元离开块的边界时,该块将其从列表中删除并将其添加到下一个块中。

我正在使用TreeSet来跟踪块中单元的顺序,这样我就可以知道哪条路径沿着路径最远。单位有一个位置字段,可以跟踪它们沿着路径走多远,位置越远,它们越远。

在我的一些块上,我注意到当它试图从TreeSet中删除一个单元时,remove返回false。我已经使用了一些断点,我可以看到该单元实际上在TreeSet中,所以我认为我的问题是我的攻击单位的compareTo方法。

这是compareTo的代码:

public int compareTo(Object other) {
    if (other != null && AttackingUnit.class.isAssignableFrom(other.getClass())) {
        AttackingUnit o = (AttackingUnit) other;
        int amount = position - o.position;
        if (amount != 0) {
            return amount;
        } else if (amount == 0 && this == o) {
            return 0;
        }
    }
    return 1;
}

我注意到这个问题的其中一个区块是单位进入顶部的一个区块,一个角落中途并退出右侧。该块有两个ArrayLists,一个用于从上到下的单元(enPath),另一个用于从左到右的单元(exPath)。下面是我遇到问题的代码:

for (int i = 0; i < exPath.size(); i++) {
    AttackingUnit unit = exPath.get(i);
    unit.stepX();
    if (unit.getX() > rightX) {
        nextBlock.addUnit(unit);
        units.remove(unit);
        exPath.remove(unit);
        i--;
    }
}

该单元位于exPath和单位(TreeSet)中,但units.remove(unit)返回false。关于如何在AttackingUnit上更改compareTo以修复此问题的任何想法?

2 个答案:

答案 0 :(得分:1)

我看到的一个问题是compareTo

} else if (amount == 0 && this == o) {

你应该对它们进行ORing(或者去除this == o检查)。就像现在一样,具有相同AttackingUnit的两个不同position实例将返回1(第一个更大)。这肯定会在树集中给出不一致的排序。

顺便说一下,你可以替换:

if (other != null && AttackingUnit.class.isAssignableFrom(other.getClass()))

if (other instanceof AttackingUnit)

更容易阅读。

答案 1 :(得分:1)

您的compareTo方法很奇怪。首先,您不应该在列表中包含任何不正确类型的元素,也不应该使用null元素,因为这样会产生问题。因此,您可以简单地在这些情况下抛出异常,而不是返回1

其次,正如史蒂夫已经指出的那样,this == o检查不正确 - 这违反了你的关系的对称性,为你提供了找不到你的元素的情况。这给出了这个更简单的版本:

public int compareTo(Object other) {
    AttackingUnit o = (AttackingUnit) other;
    int amount = position - o.position;
    return amount;
}

第三,确保单元位于TreeSet中时位置(即比较结果)不会改变。如果位置必须更改,请先从集合中删除元素,更改位置,然后重新添加。