我是一个具有一点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的处理是什么允许破解代码(例如,类型不匹配)进行编译?
提前感谢您的任何反馈。
答案 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库设计者没有这样做。