Search code examples
javainterfaceenumscomparable

How to make enums use their compareTo method when they implement an interface?


The structure is like this:

public interface ItemList{ }

public enum ItemList1 implements ItemList {

    Apple,
    Orange;
}

public enum ItemList2 implements ItemList {

    Banana,
    Grapes;
}

and 5 more such enums

The requirement is to use these enums as Keys in a Map, and in those Maps I have put key as:

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

The ItemList which goes into the map is decided on runtime. And I need to use a sorted Map like TreeMap for other operations. So, the TreeMap is unable to compare the key enums obviously because I have declared them as ItemList supertype.

So, I searched other questions and did something like this so that enums could use their compareTo method:

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

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

But this doesn't solve the problem. I am still getting the same "ClassCastException" when I tried to retrieve a TreeMap which had my enums as Keys.

Please suggest if I am doing anything wrongly here, or what can be an other way to solve this purpose?

EDIT: Link to the solution which I followed, but it's not working: How to implement an interface with an enum, where the interface extends Comparable?

EDIT 2 Problem identified. Sorry guys. My map was getting populated with different types of enums as keys, when all the keys should belong to same type for sorting to work.


Solution

  • Well, you already found out that it was the actual content of the Map, not the declaration of the classes that caused the exception, but it’s worth noting that using collections comparing these enums is easier than you think.

    E.g. TreeMap doesn’t care whether its declared Generic type has a comparable key or not. If you have class declarations like

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

    you can simply use it as

    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);
    

    without problems; it even works if you declare the map as TreeMap<Object,Object>.

    Note that some methods require comparable types when requesting natural order by not specifying a Comparator, e.g. with the type declarations above,

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

    does not compile, however, you can easily circumvent it by requesting the natural order via a null Comparator:

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

    So it’s not necessary to mess around with complicated type declarations like ItemList<SelfType extends ItemList<SelfType>> in most cases.