5

我有一个包含包装器的 TreeSet,这些包装器将Foo对象存储在某个位置position,定义如下:

class Wrapper implements Comparable<Wrapper> {
  private final Foo foo;
  private final Double position;

  ...

  @Override boolean equals(Object o) {

    ... 

    if(o instanceof Wrapper)
        return o.getFoo().equals(this.foo);

    if(o instanceof Foo)
        return o.equals(this.foo);
  }

  @Override public int compareTo(MarkerWithPosition o) {
      return position.compareTo(o.getPosition());
  }
}

NavigableSet<Wrapper> fooWrappers = new TreeSet<Wrapper>();

因为我希望 myTreeSet被排序position但可以被搜索foo。但是当我执行这些操作时:

Foo foo = new Foo(bar);
Wrapper fooWrapper = new Wrapper(foo, 1.0);
fooWrappers.add(fooWrapper);

fooWrapper.equals(new Wrapper(new Foo(bar), 1.0));
fooWrapper.equals(new Foo(bar));
fooWrappers.contains(fooWrapper);
fooWrappers.contains(new Wrapper(foo, 1.0));
fooWrappers.contains(new Wrapper(new Foo(bar), 1.0));
fooWrappers.contains(new Wrapper(foo, 2.0));
fooWrappers.contains(foo);

我得到:

true
true
true
true
true
false
Exception in thread "main" java.lang.ClassCastException: org.gridqtl.Marker cannot be cast to java.lang.Comparable
    at java.util.TreeMap.getEntry(TreeMap.java:325)
    at java.util.TreeMap.containsKey(TreeMap.java:209)
    at java.util.TreeSet.contains(TreeSet.java:217)

当我希望他们全部返回true时,似乎没有像 API建议TreeSet.contains的那样使用我的方法。我需要覆盖另一种方法吗?equals

4

2 回答 2

10

TreeSet 是一个确实使用的 Set 实现compareTo,如javadoc-强调我的解释:

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

于 2012-07-30T13:17:39.143 回答
0

TreeSet 是一个有序集合。

equals无法为您提供订购信息,因此 TreeSet 必须使用其他东西。

这个“其他东西”是Comparable接口,或者它的表亲Comparator接口。

这两个接口都提供了有关如何对一个类的 2 个对象进行排序的信息。

于 2012-07-30T13:19:05.977 回答