首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么TreeSet声明为TreeSet<E>而不是TreeSet<E扩展Comparable<E>>

为什么TreeSet声明为TreeSet<E>而不是TreeSet<E扩展Comparable<E>>
EN

Stack Overflow用户
提问于 2016-03-03 11:18:12
回答 3查看 308关注 0票数 3

我在使用TreeSet时,在调用TreeSet#add()方法时找到了一个ClassCastException

代码:

代码语言:javascript
复制
public class Testing {
    public static void main(String[] args) {
        TreeSet<Testing> ts = new TreeSet<>();
        ts.add(new Testing());
    }
}

输出:

代码语言:javascript
复制
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对象来对它们进行排序,那么为什么不将其类型声明为

代码语言:javascript
复制
public class TreeSet<E extends Comparable<E>>

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-03-03 11:19:28

TreeSet的元素不必实现Comparable,因为您可以将Comparator传递给TreeSet的构造函数之一,以便对不实现Comparable的元素(或者当您希望使用Comparable定义的自然排序以外的排序时确实实现Comparable的元素)强制排序。

票数 7
EN

Stack Overflow用户

发布于 2016-03-03 11:31:33

正如在其他答案中提到的,如果指定了自定义TreeSet,那么Comparable键可能不是Comparator。仍然有可能对您的情况执行编译时检查。假设我们将默认构造函数设置为私有,并提供一个静态工厂方法:

代码语言:javascript
复制
public class TreeSet<E> {
    private TreeSet() {...}

    public static <E extend Comparable<? super E>> TreeSet<E> newSet() {
        return new TreeSet<>();
    }
}

这样,您将被迫使用TreeSet.newSet(),如果将编译时类型检查分配给TreeSet<Testing>,并且Testing是不可比拟的,那么编译时类型检查就会失败。为什么不做呢?因为泛型只出现在Java1.5中,而TreeSet出现在Java1.2中,所以这不是一个问题。现在我们必须处理向后兼容性问题。

票数 1
EN

Stack Overflow用户

发布于 2016-03-03 11:28:33

按照它的实现方式,您可以订购那些无法自行决定是否应该在较高或较低的位置上订购的项目。

以现实生活为例:你有一场选美比赛。如果你问其中一个女孩她是否比她旁边的那个漂亮,她会说是的。你不能仅仅通过问他们就把他们按顺序排列。所以你需要其他人来负责排序,比较器。

这允许您订购无法将自己与另一项进行比较的项目。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35770730

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档