Search code examples
javasortinggenericscomparable

Java - Collection.Sort over Interface Objects


I have a number of abstract classes each superclassing three or four concrete ones and of the form:

public abstract class TypeOfMapObject extends IrrelevantClass implements Serializable, MapObject, Comparable<MapObject>
{
  //irrelevant stuff
  @Override
  public int compareTo(MapObject m)
  {
    //specific algorithm for natural ordering
  }
}

Elsewhere in my code I have an ArrayList<MapObject> (which is being populated correctly, I have checked that) called tempMapObjectsArray I want to sort that ArrayList using Collections.sort(tempMapObjectsArray) (or, rather, I want to sort that ArrayList and it seems Collections.sort() is the best way to do it. The specific way its sorted isn't important).

It's not compiling and giving the message (in Netbeans):

no suitable method found for sort(java.util.ArrayList<Model.MapObject>)
 method java.util.Collections.<T>sort(java.util.List<T>,java.util.Comparator<? super T>) is not applicable
 (cannot instantiate from arguments because actual and formal argument lists differ in length)
 method java.util.Collections.<T>sort(java.util.List<T>) is not applicable
  (inferred type does not conform to declared bound(s)
   inferred: Model.MapObject
   bound(s): java.lang.Comparable<? super Model.MapObject>)

It seems that I am defining the generic wrong in the TypeOfMapObject class, but this is the first time I have really used generics and it's reached the stage where I am simply trying things more or less at random. I'm reading through the tutorial but so far it's simply not "clicking" what I'm doing wrong.

EDIT: Each of the subclasses of the various abstract classes need to be comparable to each other - so if I have abstract classes TypeofMapObject1, TypeOfMapObject2 etc, then I need to be able to compare a subclass of 1 to a subclass of 2.


Solution

  • Match the Comparable type with the class:

    public abstract class TypeOfMapObject extends IrrelevantClass implements Serializable, MapObject, Comparable<TypeOfMapObject> {
        @Override
        public int compareTo(TypeOfMapObject m)
        {
            //specific algorithm for natural ordering
        }
    }
    

    Or simply don't define the compareTo method in your abstract class - leave it for the subclass to implement.


    To address edit to question:

    If you want to compare different subtypes, have them implement a method that returns a value (say String) with which they may be compared. For example:

    public abstract class TypeOfMapObject extends IrrelevantClass implements Serializable, MapObject, Comparable<TypeOfMapObject> {
        @Override
        public int compareTo(TypeOfMapObject m)
        {
            return compareValue().compareTo(m.compareValue());
        }
    
        // subclasses to return their value to compare
        protected abstract String compareValue();
    }
    

    The type returned from the compareValue() can be anything compareable, eg Integer, Date, whatever.