Erasure in Java and its implications
What happens to generics when they get compiled? It turns out they are converted into casts. (Which may feel quite odd, as we used generics as a way of avoiding casting!)
Erasure is a fancy word for this process, from the idea that the generics themselves are erased.
Here are some examples below of how the types are erased:
To give the correct type information in the compiled code, the compiler then inserts casts and/or bridge methods.
Cast example:
gets converted to
An example of a Bridge Method is at the bottom of this post, since it’s not needed to understand the rest of the post.
Implications of erasure
Once your code gets compiled, your generics become collections of rawtypes and cleverly placed casts. The result is that some of your generics may be erased and not adequently represented, because there isn’t a way of representing what you want. Thus, your code may have less information about your types than you think.
If you add a generic that is useless, your compiler will raise an error. The compiler is actually trying to be helpful, letting you know that generic type you added doesn’t actually do anything.
The following are some common examples of this.
Overloading
If the generic type is the only difference in the method signature, then overloading doesn’t work. This is because at compile time, the compiler will remove the generic type and thus the difference between the two methods.
So the following two method declarations:
will both be erased to
and you end up with two identical method declarations.
instanceof
If you do:
You’ll get the compile error Illegal generic type for instanceof
. If this was allowed, then all generic types would compile to
and you would not be able to distinguish between them.
Exceptions
will give you Generic class may not extend java.throwable.lang
. Similarly to above, this is compiled to:
and thus the generic types cannot be distinguished from each other.
Static variables
This isn’t a product of Erasure, but this is another example where generics can’t be used:
Here, os
is all three of Smartphone, Pager, and TabletPC type, which is clearly nonsense.
Performance issues
All generics are erased to some sort of Object or Interface. This means you cannot use primitive type such as an int
for generics. Instead you would have to use Integer. So, you cannot do:
It would have to be
These Objects require more memory than the primitive types, and thus impact performance in our programs.
Side note - Bridge methods
These are used when we extend a generic class or interface. The example below has been shamelessly ripped from the javadocs website.
After type erasure it looks more like this:
Due to the removal of the generic types, the ChildNode setData method signature does not match the parent class’s signature. Without further help from the compiler, the method would not be overloaded.
A bridge method is created by the compiler to get around this problem. It copies the same method signature from the parent class, and then casts the arguments.