为什么TreeSet会抛出ClassCastException

在下面的代码我试图添加两个员工对象

Set s = new TreeSet(); s.add(new Employee(1001)); s.add(new Employee(1002)); 

但Result是java.lang.ClassCastException:

 Exception in thread "main" java.lang.ClassCastException: Employee cannot be cast to java.lang.Comparable at java.util.TreeMap.put(TreeMap.java:542) at java.util.TreeSet.add(TreeSet.java:238) at MyClient.main(MyClient.java:9) 

但如果我换到。

 Set s = new TreeSet(); s.add(new Employee(1001)); 

要么

 Set s = new HashSet(); s.add(new Employee(1001)); s.add(new Employee(1002)); 

那么结果就是成功也没有例外。 我没有在上面的代码中进行任何类转换活动。 请帮我找出原因并建议我解决方案。

Employee必须实现Comparable ,或者在创建TreeSet时需要提供比较器 。

这在SortedSet的文档中有详细说明:

插入到有序集中的所有元素必须实现Comparable接口(或者由指定的比较器接受)。 此外,所有这些元素必须是可相互比较的: e1.compareTo(e2) (或comparator.compare(e1, e2) )不得为有序集合中的任何元素e1e2抛出ClassCastException 。 尝试违反此限制将导致违规方法或构造函数调用抛出ClassCastException

如果您不满足这些要求,则排序集将不知道如何比较其元素并且无法运行。

因此,当您使用TreeSet时,需要实现与Employee对象的Comparable接口,因为TreeSet希望保持元素的排序。

如果未设置自定义Comparator TreeSet需要元素实现ComparableHashSet使用equals / hashCode合约。

您只能在TreeSet添加一个不实现Comparable元素,因为它不需要与其他元素进行比较。

看一下TreeMap.put(K key, V value)源代码,你就会清楚地看到所有问题背后的原因( TreeSet基于TreeMap ,因此是源参考)。

从TreeSet #add(E) JavaDoc:

抛出 :ClassCastException – 如果指定的对象无法与此set中当前的元素进行比较

基本上你需要的是让Employee实现Comparable或者为TreeSet对象提供Comparator

如果检查TreeMap代码,您将看到如果在Map对象中找不到比较器,它将尝试将密钥(您的Employee对象)直接转换为Comparator

 ... Comparable k = (Comparable) key; ... 

TreeSetSortedSet一个实现。 您可以让Employee实现Comparable接口或为TreeSet提供适当的Comparator

 Set s = new TreeSet(new EmployeeComparator()); 
 //class Employee public class Employee implements Comparable{ int id; Employee(int id){ this.id=id; } public int compareTo(Employee e){ //implementing abstract method. if(id>e.id){ return 1; } return 0; } //class TreeSet Set emp =new TreeSet(); Employee eobj1 = new Employee(2); Employee eobj2 = new Employee(3); emp.add(eobj1); emp.add(eobj2); for (Student ss:emp) { System.out.println(ss.rollno); } } //output: 2 // 3