Okay, I’ve had some quality time with Java5 at my newest gig, and I’m starting to understand the great controversy behind Java generics. There was a particularly painful insight I just had that has officially flipped me from stalwart supporter to reluctant supporter, and I’d like to share that with the world so they don’t have to hunt this bug down themselves.
The particular insight runs as follows. Assume that you have a class FooBar that takes parameterized type T. And assume you have a method that looks something like this:
public T create() {
final Object created = makeIt();
try {
final T out = (T) created;
return out;
} catch (ClassCastException cce) {
return null;
}
}
Now, if I have a Foobar<Integer> object kicking around, and call create() in such a state that it makeIt() returns the String “42″, what would you expect to come out of create()?
Well, my thought was as follows.
Reduction 1:
public T create() {
final Object created = "42";
try {
final T out = (T) created;
return out;
} catch (ClassCastException cce) {
return null;
}
}
Reduction 2:
public Integer create() {
final Object created = "42";
try {
final Integer out = (Integer) created;
return out;
} catch (ClassCastException cce) {
return null;
}
}
Reduction 3:
public Integer create() {
try {
final Integer out = (Integer)"42";
return out;
} catch (ClassCastException cce) {
return null;
}
}
Reduction 4:
public Integer create() {
return null;
}
So, I’m thinking the answer should be null.
What I forgot is that Java implemented generics through type erasure (cite). So the reductions actually look like this:
Reduction 1:
public T create() {
final Object created = "42";
try {
final T out = (T) created;
return out;
} catch (ClassCastException cce) {
return null;
}
}
Reduction 2:
public Object create() {
final Object created = "42";
try {
final Object out = created;
return out;
} catch (ClassCastException cce) {
return null;
}
}
Reduction 3:
public Object create() {
return "42";
}
And that method — that one which the compiler dilligantly guarantied would only be used in places where it returns Integer objects — just returned a String.
Seriously.
I’ve got the unit tests to prove it.
EDIT: Oh, yeah, and there’s no way to go from <T> to something like T.class.
Related posts:
Pingback: Enfranchised Mind » JConch’s CacheMap: Change of Tact
Pingback: The Cheap Sitcom Clip Scene Blog Post | Enfranchised Mind