Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/drupal/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么Set.contains()似乎没有使用o.equals()?_Java_Set_Equals_Comparable - Fatal编程技术网

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

Java 为什么Set.contains()似乎没有使用o.equals()?,java,set,equals,comparable,Java,Set,Equals,Comparable,我有一个包含包装器的树集,包装器将Foo对象存储在某个位置,定义如下: class Wrapper implements Comparable<Wrapper> { private final Foo foo; private final Double position; ... @Override boolean equals(Object o) { ... if(o instanceof Wrapper) return o

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

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>();
我得到:

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
时,似乎
TreeSet.contains
没有使用我的
equals
方法作为API。还有其他方法需要覆盖吗?

TreeSet是一个集合实现,它确实使用了
compareTo
,如-emphasis mine中所述:

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


树集是一个有序集

equals
无法提供订购信息,因此TreeSet必须使用其他信息

这个“其他东西”是
可比较的
接口,或者它的近亲
比较器
接口


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

可能的重复正是因为树集合中的比较与等式不一致,这是否意味着我也应该创建一个
compareTo(Foo)
?但是我的
Compariable
无法参数化。@fophillips,你真的不能做你想做的事。您不能强制以一种方式对
TreeMap
进行排序,而是以另一种方式进行搜索。我要做的第一件事是阻止你的
equals
方法像现在这样干扰不同的类型,并在集合中进行显式线性搜索…这是你无论如何都需要做的,因为你希望排序与搜索不同。这意味着foo1.equals(foo2)应该与foo1.compareTo(foo2)==0,否则你会有意想不到的结果。这里不是这样,因为Wrapper(foo,1)等于Wrapper(foo,2),但compareTo不返回0。您可能想重新考虑您的设计。但声明“强烈建议,但并非严格要求(x.compareTo(y)==0)==(x.equals(y))”,因此我不确定为什么我尝试这么做是错误的。建议这样做是因为违反该建议会导致奇怪、混乱的行为……正如您刚刚发现的那样。(行为仍然是定义良好的——它从不使用
equals
,只使用
compareTo
——但正如引用的Javadoc中所述,如果您希望
接口保证保持不变,那么您的比较器“必须与equals一致”)
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)