开发者

Best practice for compareTo() when argument must be typed of super class

I'm looking for best practice for the definition of the compareTo() method in the case where the class implements Comparable. Thus, the signature of the method has to be

public int compareTo(BaseClass arg)

The obvious thing to do first is check if the arg is an instanceof this class, and if so, cast to the class, and compare the members. But if the argument is not of this class, but rather some other class that also implements BaseClas开发者_JAVA技巧s, what do I return so that its reflexive?

I know, the very best practices would be to define compareTo() only for the class it is, but that water is over the dam.


Quote from Effective Java, Item 12:

Let’s go over the provisions of the compareTo contract. The first provision says that if you reverse the direction of a comparison between two object refer- ences, the expected thing happens: if the first object is less than the second, then the second must be greater than the first; if the first object is equal to the second, then the second must be equal to the first; and if the first object is greater than the second, then the second must be less than the first. The second provision says that if one object is greater than a second, and the second is greater than a third, then the first must be greater than the third. The final provision says that all objects that compare as equal must yield the same results when compared to any other object.

One consequence of these three provisions is that the equality test imposed by acompareTo method must obey the same restrictions imposed by the equals con- tract: reflexivity, symmetry, and transitivity. Therefore the same caveat applies: there is no way to extend an instantiable class with a new value component while preserving the compareTo contract, unless you are willing to forgo the benefits of object-oriented abstraction (Item 8). The same workaround applies, too. If you want to add a value component to a class that implements Comparable, don’t extend it; write an unrelated class containing an instance of the first class. Then provide a “view” method that returns this instance. This frees you to implement whatever compareTo method you like on the second class, while allowing its cli- ent to view an instance of the second class as an instance of the first class when needed.

You should do what @BalusC recommended in his comment -- use the compareTo() method of the base class for all children classes, OR do the workaround suggested above by creating an unrelated class containing an instance of the first class.


Your mistake is in your question. You do not have to implement public int compareTo(BaseClass arg). You have to implement 'public int compareTo(YourClass arg)'.

In this case you do not have to use instanceof and perform cast. This is why generics were introduced: to avoid casting.

But if you still want to use base class as an argument do at least the following:

public class Test {

}

class SubTest <T extends Test> implements Comparable<T> {
    @Override
    public int compareTo(T o) {
        // add your code with instanceof here
        return 0;
    }
}

At least this approach requires that the argument is subclass of your base class.


In this context reflexive means obj.compareTo(obj) == 0. What do you mean by reflexive here?

As far as the specified contract for compareTo(T o), the required semantics are for you to throw a ClassCastException if the classes involved can not meaningfully be compared.

e.g. Given

class Fruit {/* ..*/ }

class Apple extends Fruit {/* .. */ }

@Ignore("bad OO")
class GrannySmithApple extends Apple {/* .. */ }

class Orange extends Fruit {/* ... */ }

one could argue that

   Fruit a = new Apple();
   Fruit b = new GrannyApple();
   Fruit c = new Orange();

   // compare apples with apple?
   // makes sense to expect an int value
   r = a.compareTo(b)

   // compare apples with oranges?
   // makes sense to expect an exception
   boolean excepted = false;
   try {
       c.compareTo(a);
   } catch (ClassCastException e) { 
      excepted = true;
   } finally {
      assert excepted : "How can we compare apples with oranges?"
   }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜