Anmol Gupta
Anmol Gupta

Reputation: 2957

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.

Upvotes: 2

Views: 308

Answers (2)

Holger
Holger

Reputation: 298599

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.

Upvotes: 1

Louis Wasserman
Louis Wasserman

Reputation: 198591

It sounds like what you should be doing is having

 private Map<? extends ItemList, OtherObject> objectList;

...to indicate objectList is a specific map of some subtype of ItemList, and then

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

or

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

to declare it as some specific type of ItemList. (You may have to store it temporarily as a Map<ItemListN, OtherObject> while you populate it, but then you can put it in objectList.

Upvotes: 0

Related Questions