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.

author · Dad
colophon · rights
picture of the day
June 12, 2005
· Technology (90 fragments)
· · Java (123 more)

By .

The opinions expressed here
are my own, and no other party
necessarily agrees with them.

A full disclosure of my
professional interests is
on the author page.

I’m on Mastodon!