2008-12-06 (Saturday)
Java Generics Misunderstanding
Today I write this down to help me understand one of the trickier things about Java generics. I hope I get it right. What I always struggle with is the meaning of generic type bounds, like
Set<A extends Wine> cellarA;
What exactly is the difference between this and the much simpler
Set<Wine> cellarB;
My first reaction always is: cellarA may contain all
kinds, i.e. subtypes, of Wine. But wait, if we have
a type hierarchy Wine > RedWine > Bordeaux,
there is nothing wrong with putting a Bordeaux into
cellarB like in
cellarB.add(new Bordeaux());
so certainly cellarB can contain all kinds of
Wine. The sligthly confusing insight is, that it is
just the other way around. It is cellarA that, once
the A is instantiated, is more restrictive in
the types it may contain. Suppose A is instantiated
in a certain context with Bordeaux. Then, in fact,
cellarA effectively has the type
Set<Bordeaux> cellarA;
and we realize that now it may not contain any kind of
Wine but more restrictively only any kind of
Bordeaux. A more complete example which compiles
and shows the difference:
public abstract class TTT {
private static class Wine {}
private static class RedWine extends Wine {}
private static class Bordeaux extends RedWine {}
private static class Cellar<A extends Wine> {
private A bottle;
public void shelve(A a) { bottle=a;}
public A retrieve() {return bottle;}
}
public static class WineStore {
private Wine bottle;
public void shelve(Wine a) { bottle=a;}
public Wine retrieve() {return bottle;}
}
static {
Cellar<Bordeaux> cellar = new Cellar<Bordeaux>();
// cellar.shelve(new Wine()); ** not allowed
cellar.shelve(new Bordeaux());
Bordeaux bordeaux = cellar.retrieve();
System.out.println(bordeaux.getClass().getName());
WineStore store = new WineStore();
store.shelve(new Wine());
Wine bottle = store.retrieve();
System.out.println(bottle.getClass().getName());
store.shelve(new Bordeaux());
bottle = store.retrieve();
System.out.println(bottle.getClass().getName());
}
}