4

I would like to implement the Comparable Interface "Twice"

public class Segment implements Comparable<Segment,Point>{
@Override
public int compareTo(Segment o) {
    return 0;
}
@Override
public int compareTo(Point p) {
    return 0;
}

Is it possible in some way? (Without using the generic interface compareTo(Object o) i think it's nasty...)

5 Answers5

3

This is not a good idea, as a design pattern. And, by the way, it is impossible in Java, because Comparable and Comparable are the same binary interface due to type erasure.

Anyway, I'll try to explain why I think that's a bad idea. When you implement Comparable you are defining a so-called "natural sorting", which is a sorting intrinsic to the class itself, a natural ordering. This ordering should involve the class and elements of the same class. So, I think (and this is a purely personal opinion) that you should only implement Comparable with the same class as the one you're implementing.

If you want to compare segments with points, this is of course a perfectly legitimate thing, as long as you have a well-defined ordering. You can achieve that by implementing a so-called "external comparator", i.e. a class that implements Comparator<X>, where X is a common superclass of Point and Segment. Java standard classes and functions are prepared to always accept an optional external comparator, because, in general, you might want to have different sorting criteria for objects of the same class.

You seem not to have a common base class/interface. Maybe you should define one, they're both geometrical entities, after all. As of now, the only thing you can do is use Comparator<Object>, and then use the instanceof operator to check the types. Which is a lot of boilerplate code, and also, I think, bad design: since you're saying the points and segments are comparable, they should have some common property that you wish to compare. Then this property should become a method of a common base class or an interface they both implement (which, indeed, might lead you to use Comparable again, but in a cleaner way).

For instance, assume that you want to compare points and segments based on their coordinates, and you want the median of a segment to be considered in sorting. Then, you could do something as:

public abstract class GeometricEntity implements Comparable<GeometricEntity> {
  protected abstract Point getSortingPoint();
  @Override
  public int compareTo(GeometricEntity other) {
    //Compare by getSortingPoint
  }
}

public class Point implements GeometricEntity {
  @Override
  protected Point getSortingPoint() { return this; }
}

public class Segment implements GeometricEntity {
  private Point ptFrom;
  private Point ptTo;
  @Override
  protected Point getSortingPoint() { return meanPoint(ptFrom, ptTo); }
}
Giulio Franco
  • 3,170
  • 15
  • 18
1

if you are doing it for Collection sorting then use Comparator

/**
 * Comparator implementation which sorts Person objects on person_id field
 */
public class SortByPerson_ID implements Comparator{

    public int compare(Object o1, Object o2) {
        Person p1 = (Person) o;
        Person p2 = (Person) o; 
        return p1.getPersonId() - p2.getPersonId();
    }
}

To sort -

 Collections.sort(perSonlist, new SortByPerson_ID());

Read more: http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-java.html#ixzz3RKoKZpB5

vivex
  • 2,496
  • 1
  • 25
  • 30
0

If you Segment and Point both implements a same Interface or they are Parent and Child, you may do that.

javamonk
  • 180
  • 1
  • 7
0

You can implement Comparable only once, but you can use Comparator interface more than once --> http://docs.oracle.com/javase/6/docs/api/java/util/Comparator.html

It has int compare(T o1, T o2) instead of Comparable's compareTo. If you want to sort your collection for example then you can use:

Collections.sort(Your list, Your new Comparator object)

RichardK
  • 3,228
  • 5
  • 32
  • 52
0

Why dont you try this way

public class Segment implements Comparable<Object>{
     @Override
     public int compareTo(Object o) {
         if(o instanceof Segment)
         {
              return 0;
         }
         else if(o instanceof Point)
         {
             return 0;
         }

     }
}

Well if you really want to do it in your way, then you can just add another method using overloading (without adding the @Override annotation).

public class Segment implements Comparable<Segment>{
    @Override
    public int compareTo(Segment o) {
        return 0;
    }

    public int compareTo(Point p) {
       return 0;
    }
}

It will be useful if you call the compareTo method manually. I am not sure what will happen they called from some other library methods.

Saif
  • 6,804
  • 8
  • 40
  • 61
  • why you think its nasty? its much cleaner than having two method with same purpose – Saif Feb 10 '15 at 10:04
  • `Comparable` is basically guaranteed to break all the implementation requirements of [`Comparable.compareTo()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html#compareTo-T-). – shmosel Jan 05 '16 at 00:48
  • @shmosel if you are talking the implementations rules required and recommended then i understand and agree. but I was try to show OP an possible way. – Saif Jan 05 '16 at 06:37