Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sort a list of generic types in Java

I have a set of classes that all share some common attributes, so I made them all extend a common base class, BaseEntity. So I have, for example Foo extends BaseEntity and Bar extends BaseEntity.

I also want lists of these Foo and Bar objects to be sortable, so I have implemented Comparable. I have the classes defined as Foo extends BaseEntity implements Comparable<Foo> and Bar extends BaseEntity implements Comparable<Bar>, and sorting of lists of Foos or Bars works as expected - and, of course, the details of the sorting are different in the different subclasses. But I can't work out how to make my sorting work when I don't know in advance whether I'll have Foos or Bars. This code, for example, fails to compile:

public class UtilityClass<T extends BaseEntity> {

  ...bunch of stuff...

  List<T> values;

  public List<T> sort() {
    Collections.sort(values);
    return values;
  }

  ...more methods...
}

with the error message Bound mismatch: The generic method sort(List<T>) of type Collections is not applicable for the arguments (List<T>). The inferred type T is not a valid substitute for the bounded parameter <T extends Comparable<? super T>>

I think the problem is that I am attempting to sort a list of BaseEntity objects, and BaseEntity itself doesn't implement Comparable. But now I face a problem: the only sensible thing to make BaseEntity objects comparable to is other BaseEntity objects, but when I add implements Comparable<BaseEntity> to BaseEntity, the compiler tells me that I've got problems now because my Foo class is trying to implement both Comparable<BaseEntity> and Comparable<Foo>, which evidently is not allowed.

I know I could sidestep this issue by dropping the implements Comparable<Foo> and just implementing Comparable<BaseEntity>, but then my compareTo methods will have to do ugly casting, and I thought that was exactly the sort of problem using generics was supposed to avoid.

What I really want to do is specify in the signature of BaseEntity that all its subclasses will be Comparable, but only to instances of the same subclass.

Any assistance gratefully received. Thanks!

like image 674
Dave Mulligan Avatar asked Jan 29 '13 07:01

Dave Mulligan


Video Answer


2 Answers

Use an intersection type, like this:

public class MyList<T extends BaseEntity & Comparable<T>> {...}

That specifies that T must be both a BaseEntity and Comparable to itself.

like image 103
Dolda2000 Avatar answered Oct 03 '22 10:10

Dolda2000


Don't use Collections.sort(List<T>), use Collections.sort(Lst<T>, Comparator<? extends T>) instead. Write the comparation code in the comparator.

like image 40
notXX Avatar answered Oct 03 '22 10:10

notXX