2016-03-03 76 views
3

我正在与TreeSet一起工作,发现ClassCastException,同时调用TreeSet#add()方法。为什么TreeSet声明TreeSet <E>而不是TreeSet <E extends Comparable <E>>

代码:

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>> 

并在编译期间进行检查,而不是在运行时抛出异常?

回答

7

一个TreeSet的元素没有实现Comparable,因为你可以通过一个ComparatorTreeSet之一“,以强制排序为不执行Comparable(元素或为做单元S构造如果要使用除Comparable定义的自然顺序以外的顺序,请执行Comparable)。

+2

我想我问得太快,没有通过整个API文档...谢谢... :) – Codebender

0

它的实施方式,您可以订购无法自行决定的商品,如果订购的商品应该比“其他”商品更高或更低。

举一个真实的例子:你有一个选美比赛。如果你问其中一个女孩是否比她旁边的女孩美丽,她会说是。你不能仅仅通过询问他们来订购它们。所以你需要别人来负责订购,比较器。

这使您可以订购无法与其他物品进行比较的物品。

1

正如在其他答案中提到的,如果指定了自定义Comparator,那么TreeSet键可能不是Comparable。它仍然可以强制编译时检查你的情况。假设我们做默认的构造私人和提供静态工厂方法代替:

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中,而在Java 1.2中出现TreeSet,这是不是一个问题。现在我们必须处理向后兼容性。

相关问题