为什么Set.contains()似乎没有使用o.equals()?

bou*_*ful 5 java equals set comparable

我有一个包含包装器的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>();
Run Code Online (Sandbox Code Playgroud)

因为我希望我TreeSet被命令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);
Run Code Online (Sandbox Code Playgroud)

我明白了:

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)
Run Code Online (Sandbox Code Playgroud)

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

ass*_*ias 9

TreeSet是一个确实使用的Set实现compareTo,正如javadoc中强调的那样:

请注意,如果要正确实现Set接口,则由set维护的排序(无论是否提供显式比较器)必须与equals一致.(参见可比或比较用于一致的精确定义与equals.)这是因为Set接口是按照equals操作定义的,但TreeSet实例使用其的compareTo执行所有元件比较(或比较)方法,所以2从集合的角度来看,通过这种方法被认为相等的元素是相等的.集合的行为即使其排序与equals不一致也是明确定义的; 它只是不遵守Set接口的一般合同.