Как заставить перечисления использовать свой метод compareTo при реализации интерфейса?

Структура такая:

public interface ItemList{ }

public enum ItemList1 implements ItemList {

    Apple,
    Orange;
}

public enum ItemList2 implements ItemList {

    Banana,
    Grapes;
}

и еще 5 таких перечислений

Требование состоит в том, чтобы использовать эти перечисления в качестве ключей на карте, и в этих картах я поместил ключ как:

public Class SomeClass {
private Map<ItemList, OtherObject> objectList;
//other code
}

ItemList, который входит в карту, определяется во время выполнения. И мне нужно использовать отсортированную карту, например TreeMap, для других операций. Таким образом, TreeMap не может сравнить ключевые перечисления, очевидно, потому что я объявил их как супертип ItemList.

Итак, я искал другие вопросы и сделал что-то вроде этого, чтобы перечисления могли использовать свой метод compareTo:

public interface ItemList<SelfType extends ItemList<SelfType>> extends Comparable<SelfType>{ }

public enum ItemList1 implements ItemList<SelfType> {
     //enum values
}

Но это не решает проблему. Я все еще получаю то же самое «ClassCastException», когда пытался получить TreeMap, в котором мои перечисления были ключами.

Пожалуйста, предложите, если я делаю что-то неправильно здесь, или что может быть другим способом решить эту цель?

РЕДАКТИРОВАТЬ: Ссылка на решение, которому я следовал, но оно не работает: Как реализовать интерфейс с перечислением, где интерфейс расширяет Comparable?

EDIT 2 Обнаружена проблема. Извините ребята. Моя карта заполнялась различными типами перечислений в качестве ключей, когда все ключи должны принадлежать к одному типу, чтобы сортировка работала.


person Anmol Gupta    schedule 08.04.2015    source источник
comment
Я не понимаю, почему карта не может отсортировать ключи. Пока он содержит только экземпляры ItemList1 или только экземпляры ItemList2, все должно работать нормально. А судя по твоему описанию, так оно и есть.   -  person JB Nizet    schedule 08.04.2015
comment
Вы не можете поместить константы из двух разных перечислений в один TreeMap в качестве ключей. В принципе, их нельзя сравнивать.   -  person Rohit Jain    schedule 08.04.2015
comment
@JBNizet Да, меня беспокоит то же самое. Я столько раз проверял. Я последовал ответу на этот вопрос stackoverflow.com/questions/7160980/   -  person Anmol Gupta    schedule 08.04.2015
comment
@RohitJain Карта заполняется только одним типом списка. Но какое перечисление будет заполнено, решается во время выполнения.   -  person Anmol Gupta    schedule 08.04.2015
comment
@AnmolGupta Тогда вы не можете получить ClassCastException.   -  person Rohit Jain    schedule 08.04.2015
comment
@RohitJain Спасибо, Рохит! Я тщательно проверил, и да, карта заполнялась различными типами списков в качестве ключей и, следовательно, исключением.   -  person Anmol Gupta    schedule 08.04.2015


Ответы (2)


Что ж, вы уже выяснили, что именно фактическое содержимое Map, а не объявление классов вызвало исключение, но стоит отметить, что использование коллекций для сравнения этих enum проще, чем вы думаете.

Например. TreeMap не волнует, имеет ли его объявленный универсальный тип сопоставимый ключ или нет. Если у вас есть объявления классов, такие как

public interface ItemList{ }
public enum ItemList1 implements ItemList { Apple, Orange }
public enum ItemList2 implements ItemList { Banana, Grapes }

вы можете просто использовать его как

TreeMap<ItemList,Object> tm=new TreeMap<>();
tm.put(ItemList1.Apple, "A");
tm.put(ItemList1.Orange, "O");
System.out.println(tm.get(ItemList1.Apple)+" is for "+ItemList1.Apple);
tm.clear();
tm.put(ItemList2.Banana, "B");
tm.put(ItemList2.Grapes, "G");
System.out.println(tm.get(ItemList2.Banana)+" is for "+ItemList2.Banana);

без проблем; это даже работает, если вы объявите карту как TreeMap<Object,Object>.

Обратите внимание, что некоторые методы требуют сопоставимых типов при запросе естественного порядка без указания Comparator, например. с объявлениями типа выше,

List<Object> list=Arrays.<Object>asList(ItemList1.Orange,ItemList1.Apple,ItemList1.Orange);
Collections.sort(list);

не компилируется, однако вы можете легко обойти это, запросив естественный порядок через null Comparator:

Collections.sort(list, null); // compiles and works

Так что в большинстве случаев нет необходимости возиться со сложными объявлениями типа, такими как ItemList<SelfType extends ItemList<SelfType>>.

person Holger    schedule 10.04.2015
comment
Благодаря Хольгеру, это расширило мои знания об использовании TreeMap. Просто чтобы убедиться, что я понял это правильно, поэтому, когда у меня нет конкретного компаратора для ключей карты дерева, он просто будет принимать естественный порядок при сортировке, верно? И для методов, которые требуют явного упоминания компаратора, я могу просто передать null в качестве компаратора для естественного порядка, который по-прежнему считается отсортированным порядком? Спасибо! - person Anmol Gupta; 13.04.2015
comment
Верно, отсутствие указания Comparator всегда подразумевает естественное упорядочение, а перегрузки, в которых отсутствует параметр, обычно применяют элементы Comparable, в то время как методы, принимающие Comparator, этого не делают. Я не могу говорить о каждом возможном методе, но документация Collections.sort и Collections.binarySearch четко определяют поведение компаратора null. - person Holger; 13.04.2015

Похоже, то, что вы должны делать, это иметь

 private Map<? extends ItemList, OtherObject> objectList;

... чтобы указать, что objectList является конкретной картой некоторого подтипа ItemList, а затем

 objectList = new TreeMap<ItemList1, OtherObject>();

or

 objectList = new TreeMap<ItemList2, OtherObject>();

объявить его как определенный тип ItemList. (Возможно, вам придется временно сохранить его как Map<ItemListN, OtherObject>, пока вы его заполняете, но затем вы можете поместить его в objectList.

person Louis Wasserman    schedule 08.04.2015
comment
Спасибо, Луис, за быстрый ответ, проблема заключалась в том, что Map в какой-то момент был заполнен различными типами перечислений, и я попросил сравнить яблоки с бананами, поэтому он выдал исключение :) - person Anmol Gupta; 08.04.2015