Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: about Collections ReverseComparator implementation

This is implemented as follows (jdk1.6.0_31):

private static class ReverseComparator<T>
implements Comparator<Comparable<Object>>, Serializable {

// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = 7207038068494060240L;

    public int compare(Comparable<Object> c1, Comparable<Object> c2) {
        return c2.compareTo(c1);
    }

    private Object readResolve() { return reverseOrder(); }
}

Why can't it instead be implemented as follows:

private static class ReverseComparator<T extends Comparable<T>> 
implements Comparator<T>, Serializable {

// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = 7207038068494060240L;

    public int compare(T c1, T c2){
        return c2.compareTo(c1);
    }
    ...
}

Is it just style, or is there some deeper reason?

EDIT: the source code shown is from Sun/Oracle jdk ((jdk1.6.0_31)).

like image 217
shrini1000 Avatar asked Apr 25 '12 07:04

shrini1000


3 Answers

I believe it is all related to the intention of making of ReverseComparator a singlenton object. Since the singlenton instance has to be defined in a static context there is no point in using any generic types.

static final ReverseComparator REVERSE_ORDER = new ReverseComparator();

This code, generates a raw type warning.

As such, the implementation of ReverseComparator, which is only used for this matter, could have been as you suggested or as it was implemented. Perhaps they chose the current implementation because it is easier to read, and because they thought that further generalization was not needed if it was only going to be privately used for this simple purpose.

Running the Java decompiler over your implementation and over the Oracle's implementation produces the same raw type byte codes.

 public int compare(java.lang.Comparable, java.lang.Comparable
 public int compare(java.lang.Object, java.lang.Object);

At the end, when the comparator is exposed through the public interface of the Collections class in the reverseOrder() method, it is impossible to avoid the casting and the unchecked warning. But we all are sure that this cannot fail, regardless of types involved.

Bottom line, IMHO I think the only reason why it was implemented as it was has to do with code clarity, or with the desire of not complicating the things more than necessary if, anyways, the unchecked warning could not be prevented. But hey, this wouldn't be the first time I am wrong ;-)

like image 135
Edwin Dalorzo Avatar answered Nov 09 '22 18:11

Edwin Dalorzo


Just guessing, but it's stored in a static field

static final ReverseComparator REVERSE_ORDER
            = new ReverseComparator();

so your version would generate a 'raw types' warning.

like image 31
artbristol Avatar answered Nov 09 '22 19:11

artbristol


I'm looking at Oracle 1.6.0_26, but I see the same code. As far as I can tell, those are functionally equivalent. You could also potentially write it like this:

private static class ReverseComparator<T> implements Comparator<Comparable<T>>, Serializable {

    // use serialVersionUID from JDK 1.2.2 for interoperability
    private static final long serialVersionUID = 7207038068494060240L;

    public int compare( Comparable<T> c1, Comparable<T> c2 ) {
        return c2.compareTo( (T) c1 );
    }

    private Object readResolve() {
        return reverseOrder();
    }
}

My only guess as to why they did it using Comparable<Object> is based on the fact that classes that implement Comparable (or Comparator) should obey the equals()contract, which does use Object. So semantically, this emphasizes that connection. Other than that, I can't think of a reason why.

like image 1
Ryan Nelson Avatar answered Nov 09 '22 19:11

Ryan Nelson