web-dev-qa-db-fra.com

Pourquoi TreeSet lève-t-il une ClassCastException?

J'essaie d'ajouter deux objets 'Employé' à un TreeSet:

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

Mais il lève une exception 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)

Mais si je n’ajoute qu’un seul objet à l’arbre:

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

Ou si j'utilise plutôt un HashSet:

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

Alors c'est réussi. Pourquoi l'exception se produit et comment puis-je résoudre le problème?

16
Rais Alam

Employee doit implémenter Comparable , ou vous devez fournir un comparateur lors de la création de TreeSet .

Ceci est expliqué dans la documentation de SortedSet :

Tous les éléments insérés dans un ensemble trié doivent implémenter l'interface Comparable (ou être acceptés par le comparateur spécifié). De plus, tous ces éléments doivent être comparables entre eux: e1.compareTo(e2) (ou comparator.compare(e1, e2)) ne doit pas jeter une ClassCastException pour aucun élément e1 et e2 dans l'ensemble trié. Si vous tentez de ne pas respecter cette restriction, la méthode ou l’appel du constructeur incriminé jettera une ClassCastException.

Si vous ne remplissez pas ces conditions, l'ensemble trié ne saura pas comparer ses éléments et ne pourra pas fonctionner.

22
NPE

TreeSet requiert des éléments pour implémenter l'interface Comparable si une Comparator personnalisée n'est pas définie. HashSet utilise plutôt le contrat equals/hashCode.

Vous ne pouvez ajouter qu'un seul élément dans TreeSet qui n'implémente pas Comparable car il n'a pas besoin d'être comparé à d'autres éléments. 

Examinez le code source TreeMap.put(K key, V value) et vous verrez clairement les raisons de toutes vos questions (TreeSet est basé sur TreeMap, d’où la référence source). 

2
denis.solonenko

De TreeSet # add (E) JavaDoc:

Lance: ClassCastException - si l'objet spécifié ne peut pas être par rapport aux éléments actuellement dans cet ensemble

En gros, vous avez besoin de laisser Employee implémenter Comparable ou de fournir un Comparator à l’objet TreeSet.

Si vous vérifiez le code TreeMap, vous verrez que si le comparateur n'a pas été trouvé dans l'objet Map, il essaiera de convertir la clé (votre objet Employee) directement en Comparator

...
Comparable<? super K> k = (Comparable<? super K>) key;
...
1
Francisco Spaeth
//class Employee
    public class Employee implements Comparable<Employee>{
    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<Employee> emp =new TreeSet<Employee>();

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

Donc, implémentez l’interface Comparable avec l’objet Employé comme vous le souhaitez lorsque vous utilisez TreeSet, car TreeSet souhaite conserver les éléments triés.

0
Martin V.

TreeSet est une implémentation de SortedSet. Vous pouvez laisser Employee implémenter l'interface Comparable ou fournir une Comparator appropriée à votre TreeSet:

Set<Employee> s = new TreeSet<Employee>(new EmployeeComparator());
0
Marco Forberg