Java and generics: handle with care – part 2

Eric | November 23, 2007

This is a follow-up to my earlier posting in which I was ranting about Java generics. Subject of the post were these two pieces of Java code:

Set<String> stringSet = new HashSet<String>();
Set<String> otherStringSet = new HashSet<String>();
otherStringSet.add((String) stringSet);
Set<List> listSet = new HashSet<List>();
Set<List> otherListSet = new HashSet<List>();
otherListSet.add((List) listSet);

The first one gives a static type error in line 3 because obviously one cannot cast a Set to a String. What confused me was that the second piece of code is (statically) well-typed. You will get a runtime error on the cast (List) listSet, but no compile time error. Why is that?

As it turns out, this is indeed according to the Java language definition. (WTF!?) So here’s the deal: (thanks to Philippe Mulet form IBM!)

Although a Set is usually obviously not a List in Java there may be some Sets that are Lists (although I wonder whether that would make sense – probably not). Because of that Sun believes you should be allowed to put this thing into a Set<List>. I have previously come across situations where I noticed that cast conversion on assignments is different from cast conversion on parameter assignment (like here). I find this really confusing…

But why does it work for String then? Well, it turns out that String is a final class. Hence, String can have no subtypes. Because of that the compiler knows that whatever you store in stringSet can only be of type String, nothing else. Therefore it can use a static type check which gives you the error message. Tricky, eh?