我正在使用TreeSet
并在调用ClassCastException
方法时找到了TreeSet#add()
。
代码:
public class Testing {
public static void main(String[] args) {
TreeSet<Testing> ts = new TreeSet<>();
ts.add(new Testing());
}
}
输出:
Exception in thread "main" java.lang.ClassCastException: Testing cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(TreeMap.java:1290)
at java.util.TreeMap.put(TreeMap.java:538)
at java.util.TreeSet.add(TreeSet.java:255)
at Testing.main(Testing.java:13)
显然,这是因为TreeSet
是一个有序集合,它需要Comparable
个对象来排序它们,所以为什么不将它的类型声明为
public class TreeSet<E extends Comparable<E>>
并在编译期间进行检查,而不是在运行时抛出异常?
答案 0 :(得分:7)
TreeSet
个元素不必实施Comparable
,因为您可以将Comparator
传递给TreeSet
&#39之一; s构造函数,以便为不要实现Comparable
的元素强加一个排序(或者当你想要使用除Comparable
定义的自然排序之外的其他排序时执行Comparable
的元素。 {1}})。
答案 1 :(得分:1)
正如其他答案中所提到的,如果指定了自定义TreeSet
,则Comparable
密钥可能不是Comparator
。仍然可以对您的案例强制执行编译时检查。假设我们将默认构造函数设为私有,并提供静态工厂方法:
public class TreeSet<E> {
private TreeSet() {...}
public static <E extend Comparable<? super E>> TreeSet<E> newSet() {
return new TreeSet<>();
}
}
通过这种方式,您将被迫使用TreeSet.newSet()
,如果将其分配给TreeSet<Testing>
并且Testing
无法比较,则编译时类型检查将失败。为什么没有这样做?因为泛型仅出现在Java 1.5中,而{1}}出现在Java 1.2中,所以这次不是问题。现在我们必须处理向后兼容性。
答案 2 :(得分:0)
实施方式,您可以订购无法自行决定的商品,如果他们的订购地点比“其他”商品更高或更低。
以现实生活为例:你有一场选美比赛。如果你问其中一个女孩她是否比她旁边的女孩更漂亮,她会说是的。你不能仅仅通过问他们就把它们放在一个订单中。因此,您需要其他人来负责订购,比较器。
这允许您订购无法与其他项目进行比较的项目。