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)