From C# to Java: Part 5
In the transition from C# 1.0 to C# 2.0, they added generics. This was an enormous improvement. Huge.
(At first I was actually kind of skeptical of generics. They reminded me of C++ templates, the use of which I had opposed on several occasions. But my 1993 reasons for advocacy against C++ templates really weren't relevant to the C# generics in 2005.)
So when I started my recent exploration of Java, one of my main questions was: Are the generics in Java 1.5 similar to generics in C# 2.0?
The answer: Sort of. Not really.
To be fair, I'll admit right up front that Java generics are better than no generics. I'm using them. They work just fine in practice for most situations.
But they're fundamentally different from C# generics. In C#, a generic is implemented at the CLR level. When you instantiate a List<T>, at runtime it will generate an implementation of a List which is specifically for type T.
When TPTB added generics to Java, one of their goals was to avoid the need for any changes to the VM. So Java's generics are implemented at the compiler level using a technique called "type erasure". Basically, the Java compiler does all the necessary type checking, but then it throws the parameterized type information away and generates regular collection code. This has a few consequences which are rather unfortunate:
- Since the parameterized type is no longer present in the
bytecode, reflection doesn't show it.
- The compiler inserts all the casts that you would have had
to write if you were using the non-generic collection class directly.
- In a generic collection of a primitive type, the parameterized type gets boxed.
So Java's generics are a nice convenience for the programmer, but they don't bring any of the performance benefits which we get from generics in C#.
Note that these tradeoffs were not accepted with no gain. The primary motivation here was to get generics without sacrificing backward compatibility. That's an important consideration, especially given the amount of Java code that already existed prior to 1.5.
But if you're coming from C# 2.0 to Java, it's good to understand how generics are different.
(For a more authoritative discussion of the topic, check out Bruce Eckel's interview with Anders Hejlsberg.)