This is an educational story (and therefore painful; O’Reilly books unfortunately were harmed in its making) about all the Java whatnots mentioned in the title, with pointers to the solutions to the problems. [Update: correction from David Hall.]
Suppose, like me, you had an interface with methods using a type (mine
called Pair
) with public constructors and getters using
Comparable.
Supose further that in the class that implemented the interface,
you had arrays like Pair[]
.
And further, that you had a bunch of client code using your interface and
stuffing
Integers
into Pairs
, because an Integer
was a
Comparable
.
Now suppose you’re porting all this to Java 1.5.
Brace yourself. At one point, I threw O’Reilly’s (pretty good actually) Java 5.0 Tiger: A Developer’s Notebook across the room and when Lauren looked askance, I apologized for missing the fireplace.
Anyhow, a
Comparable
isn’t a Comparable
any more, it’s a
Comparable<T>
, and an Integer
isn’t a
Comparable
any more, it’s
a Comparable<Integer>
, and you’re going to get
unsafe-comparison whines every time you try to compile anything (and worse,
your API’s customers will too).
Then when you try to paramaterize it all with generics
you’ll discover that Comparable
is kind of surprising, and then
you’ll discover there are all sorts of problems with arrays of parameterized
types.
Anyhow, after pursuing a maze of twisty little Java-Generics passages around
the Internet (I read
Gilad’s
explanation of the unsafeness of generic arrays seven
or eight times, even), I stumbled on the key resources to explain this stuff:
Peter Williams of Sussex University on
Generic
arrays, and this
excerpt
from Java in a Nutshell by David Flanagan, which I totally have to buy.
To summarize, the key incantations are:
public interface Page<K extends Comparable<K>>
public class LocalPage<K extends Comparable<K>> implements Page<K>
Pair<K>[] p = (Pair<K>[]) new Pair[size];
On that last one, you have to be prepared to ignore the unchecked-cast warning (and it would be good to read Gilad’s piece so you understand why it happens).
Update: David Hall writes that the above should really be (if you want to know why, go check his explanation):
public interface Page<K extends Comparable<? super K>>
public class LocalPage<K extends Comparable<? super K>> implements Page<K>
Some day I must find out why generic declarations extend
rather than implement
interfaces. Grr.
At the end of the day, my interfaces are all nicely parameterized and their
customers won’t be getting any warnings.
And I do think that making Comparable
a little less of a blunt
instrument was probably a good idea; after all, even if Fish
is a
Comparable
, the following is probably unsound:
if ((new Fish(freshwater)).compareTo(new Bicycle(racing)) < 0)
Still, education is painful.