2

我有一个类的实例,我想按特定顺序对其进行排序,但也能够使用不同的标准判断一个实例是否存在于集合中。例子:

public class Foo {
    int x;
    int y;

    public Foo(int x, int y) { this.x = x; this.y = y }

    // equality determined by value of 'x':
    @Override 
    public boolean equals(Object obj) {
        if (obj instanceof Foo) {
            return ((Foo)obj).x == this.x;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.x;
    }

    @Override
    public int compareTo(Foo foo) {
        if (this.x < foo.x return -1;
        else if (this.x > foo.x return 1;
        return 0;
    }
}

...

// Would like to keep a set of Foos, but sorted by 'y' value.
// Passing in an explicit comparator which sorts on 'y'.
SortedSet<Foo> test = new TreeSet<Foo>(new ComparatorFoo());

public static class ComparatorFoo implements Comparator<Foo> {
    @Override
    public int compare(Foo o1, Foo o2) {
        if (o1.y < o2.y) return -1;
        else if (o1.y > o2.y) return 1;
        return 0;
    }
}

现在尝试:

test.add(new Foo(3, 4));
test.add(new Foo(1, 2));
test.add(new Foo(5, 6));

// sorts by 'y' ok.
for (Foo foo : test) {
    System.out.println(foo.toString());
}

// but can't find an instance with the same 'x' value:
test.contains(new Foo(1, 999));

我是否需要保留两个单独的数据结构才能做到这一点?(一个用于排序,一个用于相等测试?)

谢谢

- - - 更新 - - - - -

最终结果:用于初始化 SortedSet 的比较器也会在调用 contains() 时使用。因此,我不能让集合按“y”排序,并通过“x”检查元素是否存在。

4

1 回答 1

4

你应该定义你的compareTo一致equals

SortedSet检查突出显示部分的java doc。

请注意,如果有序集合要正确实现 Set 接口,则由有序集合维护的排序(无论是否提供显式比较器)必须与 equals 一致。(请参阅 Comparable 接口或 Comparator 接口以了解与等于一致的精确定义。)这是因为 Set 接口是根据等于操作定义的,但排序集使用其 compareTo(或比较)方法执行所有元素比较,因此从排序集的角度来看,此方法认为相等的两个元素是相等的。一个有序集合的行为是明确定义的,即使它的排序与equals不一致;它只是不遵守 Set 接口的一般约定。

更改您的比较器,如下所示

public static class ComparatorFoo implements Comparator<Foo> {
    @Override
    public int compare(Foo o1, Foo o2) {
        if (o1.x < o2.x)
            return -1;
        else if (o1.x > o2.x)
            return 1;
        return 0;
    }
}

它会回报你true

于 2012-10-30T17:57:31.917 回答