我有一个包含包装器的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>();
因为我希望我的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);
我明白了:
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 suggests。我需要覆盖另一种方法吗?
答案 0 :(得分:9)
TreeSet是一个确实使用compareTo
的Set实现,正如javadoc中强调的那样:
请注意,如果要正确实现Set接口,则由set维护的排序(无论是否提供显式比较器)必须与equals一致。 (请参阅Comparable或Comparator以获得与equals一致的精确定义。)这是因为 Set接口是根据equals操作定义的,但TreeSet实例使用compareTo(或compare)方法执行所有元素比较,所以从这个方法来看,两个被认为相等的元素是相等的。集合的行为即使其排序与equals不一致也是明确定义的;它只是不遵守Set接口的一般合同。
答案 1 :(得分:0)
TreeSet是一个有序集。
equals
无法为您提供订购信息,因此TreeSet必须使用其他内容。
此“其他内容”是Comparable
界面或其堂兄Comparator
界面。
两个接口都提供有关如何订购类的2个对象的信息。