Java Generics&集的集合

时间:2012-04-14 19:09:50

标签: java generics containers

我是一个具有一点C ++经验的Java noob,我正在尝试用以下几行创建一套Java集合(类似于C ++中的那样):

Set< Set< String > > collection = new TreeSet< Set< String > >();
Set< String > entry =  new TreeSet< String >();
collection.add( entry );

这种构建很好,但是当程序执行时,会抛出java.util.TreeSet cannot be cast to java.lang.Comparable异常。

如果没有重新实现轮子,如何在Java中拥有一组集合?

此外,Java的处理是什么允许破解代码(例如,类型不匹配)进行编译?

提前感谢您的任何反馈。

3 个答案:

答案 0 :(得分:7)

TreeSet的合同中,要求规定所有条目必须为Comparable,否则您必须提供Comparator。 (这也是您没有看到编译时错误的原因:在没有明确Comparable的情况下,条目仅转换为Comparator。)

它与泛型无关,它来自TreeSet本身的实现:因为它是一个二叉树,只有条目可以以某种方式排序才有意义。

如果您更多地了解您的具体问题,我们可以帮助您找到所需的确切数据结构,但一般情况下,如果您不关心集合中元素的顺序,{{1} } 用来。而且,一般来说,HashSet Set通常是设计草率的标志。

答案 1 :(得分:2)

如果要将对象添加到TreeSet集合,则该对象的类型必须实现Comparable接口,TreeSet本身不会。或者,您可以通过使用不同的构造函数创建TreeSet来提供Comparator

对于这个特定场景使用TreeSet没有任何意义,因为根据定义,这是一个有序集合,您似乎不需要对元素进行排序。您可以尝试使用HashSet

此外,为了回答第二个问题,此错误仅在运行时出现,因为您正在利用多态行为,即您正在添加Set,实际上在运行时绑定到TreeSet。在编译时不知道此信息。

答案 2 :(得分:0)

问题是TreeSet从泛型的角度来看并不是完全“类型安全的”,因为它需要能够接受自定义比较器使用自然顺序

如果TreeSet仅使用自然排序,则可以将其声明为TreeSet<E extends Comparable<? super E>>并且它将是类型安全的 - 与自身无法比较的类型根本无法用作参数。另一方面,如果它总是使用比较器,它也是类型安全的。

但是现在它的设计方式允许你创建一个没有比较器的TreeSet(因此使用自然排序),其元素类型与自身不可比。没有编译时检查来强制执行此操作。只有在运行时才能注意到失败。

实际上有一种方法可以修复TreeSet。它可以支持自然排序和自定义比较器,并且是类型安全的:

  • 拥有一个接受自定义比较器的构造函数

  • 没有自然排序情况的构造函数。相反,有一个工厂方法来创建一个使用自然顺序的TreeSet。工厂方法可以具有绑定<E extends Comparable<? super E>>的泛型类型,该类型要求类型与其自身相当

我不知道为什么Java库设计者没有这样做。