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
Pair) with public constructors and getters using
Supose further that in the class that implemented the interface,
you had arrays like
And further, that you had a bunch of client code using your interface and
Pairs, because an
Integer was a
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.
Comparable isn’t a
Comparable any more, it’s a
Comparable<T>, and an
Integer isn’t a
Comparable any more, it’s
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
Anyhow, after pursuing a maze of twisty little Java-Generics passages around
the Internet (I read
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
arrays, and this
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
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.