Multi-Dimensional Arrays
Object-Orientated Design: Polymorphic Sorting
One limitation of the sort routines developed so far is that they only
work on one particular type of data. If you've written an insertion
sort to sort ints, you can't use it to sort doubles. What would be
far more desirable is a polymorphic sort method—that is, one method
that could sort any kind of data. This is easily done by making use of
Java wrapper classes, such as Integer and Double, together with the
java.lang.Comparable interface, which is specially designed for this
purpose.
The java.lang.Comparable interface consists of the compareTo()
method:
By implementing compareTo(), a class can impose an order on its objects. The Comparable interface is implemented by all of Java's wrapper
classes—that is, by Integer, Double, Float, Long, and so on (Fig. 9.24).
As we saw in Chapter 8, Java interfaces allow us to create a form of multiple inheritance. For example, as Figure 9.24 shows, an Integer is both an
Object and a Comparable. One implication of this is that an Integer
can be used in any method that takes either an Object parameter or a
Comparable parameter.
The compareTo() method takes an Object parameter and returns an
int. It is meant to be invoked as o1.compareTo(o2), where o1 and o2
are objects of the same type. Classes that implement compareTo() must
abide by the following rules for its return value:
In other words, if o1 < o2, then o1.compareTo(o2) will return a negative integer. If o1 > o2, then o1.compareTo(o2) will return a positive integer. And if o1 and o2 are equal, then o1.compareTo(o2) will
return 0.
For a class that implements Comparable, we can use the compareTo()
method to help sort its elements. For example, the following revised
version of insertionSort() method can be used to sort any array of
Comparable objects—that is, any array of objects whose class implements Comparable:
In this version, the parameter is an array of Comparable. Thus, we can
pass it any array whose elements implement Comparable, including an
array of Integer or Float, and so on. Then, to compare elements of a
Comparable array, we use the compareTo() method:
Note that our algorithm no longer refers to ints, as in the original insertion sort. Indeed, it doesn't mention the specific type—Integer,
Float, or whatever—of the objects that it is sorting. It refers only to
Comparables. Therefore, we can use this method to sort any type
of object, as long as the object's class implements the Comparable
interface. Thus, by using Comparable, we have a more general
insertionSort() method, one that can sort any one-dimensional array
of Comparables.
The TestSort class (Figs. 9.25 and 9.26) provides an example of how to use the polymorphic sort() method.
It contains three methods: The sort() method that we just described;
a polymorphic print() method, which can be used to print the values of any array of Comparable; and a main() method. The main()
method creates arrays of Integer and Float and then uses the polymorphic sort() method to sort them. Note how the print() method
uses the polymorphic toString() method to print the elements of a
Comparable array.
This example of polymorphic sorting illustrates once again the great
power of inheritance and polymorphism in object-oriented programming.
The Integer and Float classes use class inheritance to inherit features
from the Object class, and they use interface implementation to inherit
the compareTo() method from the Comparable class. By implementing versions of the toString() and compareTo() methods that are appropriate for these wrapper classes, Java makes it easier to use Integer
and Float objects in a variety of contexts. Taken together, inheritance and polymorphism enable us to design very general and extensible algorithms. In this example, we defined a sort() method that can sort an
array containing any kind of object as long as the object implements the
Comparable interface.