This morning I ran into something that most C# developers never think about – type erasure. Many .NET developers who have written code that either utilizes generic classes or is a generic class don’t really know about type erasure, nor do they care. It’s perfectly acceptable for a C# developer not to care about type erasure.

However, when you have a C# background and you start attempting to write generics code in Java, type erasure will almost certainly rear its ugly head and it will probably make you scratch your head (or even slam that head on your desk repeatedy).

When C# implemented Generics, it did so atop a brand new CLR. When Java implemented generics, it did so under the false presumption that they were not allowed to change the compiled class file format. This causes a couple of wrinkles, including:

  • You can’t have a non-generic class Bob and a generic class Bob<M> in the same package. These two end up being the exact same type. C# programmers aren’t used to this restriction.
  • Generic methods retain the same name. This is the one that bit me this morning, and the focus of the code sample I’m about to show. This means you cannot overload based on type parameters to generic method arguments.
  • Even though you don’t see the runtime typecasting, it’s being done for you by the JVM. This means that, unlike C# generics which actually give us typecast-free performance, Java generics confer no performance improvement over their non-generic counterparts.

So, let’s take a look at some method overloading that I thought should work just fine:

public void doSomething(Sword<Air> weapon) { ... }
public void doSomething(Sword<Earth> weapon) { ... }
public void doSomething(Sword<Fire> weapon) { ... }

I thought that depending on the type binding of the incoming argument to the doSomething method, the JVM would happily choose the most appropriate method for me and allow me to have separate implementations. As it turns out, this code won’t even compile.

What it does is tell me that the various arguments to the overload of doSomething all “have the same erasure“. This means that after the Java compiler has happily stripped the generic type parameter from all of the methods in my code, it can no longer tell the difference between method signatures. UGH.

There are some elegant (and some not-so-elegant) ways around this problem, but the bottom line is that any C# developer who has somehow been dipped into the pool of Java absolutely needs to know what type erasure is and how it affects Java generics and related code.