2016-03-03 8 views
3

Я работал с TreeSet и нашел ClassCastException при вызове метода TreeSet#add().Почему TreeSet объявлен TreeSet <E> вместо TreeSet <E расширяет Сопоставимые <E>>

Код:

public class Testing { 
    public static void main(String[] args) { 
     TreeSet<Testing> ts = new TreeSet<>(); 
     ts.add(new Testing()); 
    } 
} 

Выход:

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 объекты для заказа их, так почему бы не заявить о своей типа

public class TreeSet<E extends Comparable<E>> 

и выполнять проверку во время компиляции вместо исключения исключения во время выполнения?

ответ

7

TreeSet «элемент s не должен осуществлять Comparable, так как вы можете передать Comparator одному из TreeSet» s конструкторов для того, чтобы наложить упорядочение для элементов, которые не реализуют Comparable (или для элементов, которые делают Внесите Comparable, если вы хотите использовать заказ, отличный от естественного заказа, определенного Comparable).

+2

Я думаю, я спросил слишком быстро, не пройдя весь документ API ... Спасибо ... :) – Codebender

0

Способ реализации, вы можете заказать предметы, которые не могут решить для себя, если они должны быть заказаны в более высоком или нижнем месте, чем в «другом» элементе.

Возьмите пример реальной жизни: у вас есть конкурс красоты. Если вы спросите одну из девушек, если она красивее, чем рядом с ней, она скажет «да». Вы не можете привести их в порядок, просто спросив их. Поэтому вам нужно, чтобы кто-то другой отвечал за заказ, компаратор.

Это позволяет вам заказывать предметы, которые не имеют возможности сравнивать себя с другим предметом.

1

Как уже упоминалось в других ответах, TreeSet ключей не может быть Comparable, если указано значение Comparator. До сих пор можно было бы обеспечить проверку времени компиляции для вашего дела. Предположим, что мы делаем конструктор по умолчанию приватным и обеспечивают статический фабричный метод вместо:

public class TreeSet<E> { 
    private TreeSet() {...} 

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

Таким образом, вы будете вынуждены использовать TreeSet.newSet() и время компиляции проверки типа потерпит неудачу, если вы назначаете его TreeSet<Testing> и Testing не сопоставимыми. Почему это не было сделано? Поскольку generics появился только в Java 1.5, а TreeSet появился в Java 1.2, это не было проблемой в эти времена. Теперь нам нужно иметь дело с обратной совместимостью.