Type Erasure

Java generics uses Types. If you are not still using java generics, following example code explains you a simple generics usage:
 
package com.sample;
 
import java.util.HashMap;
import java.util.Map;
 
public class TypeErasure {
  public static void main(String args[]) {
 
    Map<String, String> languageMap = new HashMap<String, String>();
    languageMap.put("1954", "FORTRAN");
    languageMap.put("1958", "LISP");
    languageMap.put("1959", "COBOL");
    String language = languageMap.get("1954");
    System.out.println("Our favourite language is "+language);
  }
}
In the above code, we instantiate a map saying that the key and values will be String. These are type parameters. It provides you type safety.
Type erasure is a process to remove the types and map it to byte code. Just trying to give a formal definition for type erasure ;-) Type erasure happens at compile time. Java compiler removes those generic type information from source and adds casts as needed and delivers the byte code. Therefore the generated byte code will not have any information about type parameters and arguments. It will look like a old java code without generics. You want to have a look at it?


Compile above given source and get a class file. Then de-compile that generate class file and you will know what is inside. You may use JAD to de-compile. Else you can avoid the round trip and use the JDK itself directly on java source and find out how the compiled source will look like. javac -XD-printflat -d .java
package com.sample;
 
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Map;
 
public class TypeErasure
{
 
    public TypeErasure()
    {
    }
 
    public static void main(String args[])
    {
        Map languageMap = new HashMap();
        languageMap.put("1954", "FORTRAN");
        languageMap.put("1958", "LISP");
        languageMap.put("1959", "COBOL");
        String language = (String)languageMap.get("1954");
        System.out.println((new StringBuilder("Our favourite language is ")).append(language).toString());
    }
}
You should note two things in the above de-compiled code.
  1. First thing is, “<String, String>” is missing.
  2. Second thing is (String)languageMap.get(“1954″) a type cast is added.
This is done by the java compiler while compiling java source code to byte code. This process is called java type erasure.

Main reason behind having type erasure at compile time is to give compatibility with old versions of java code where you don’t have generics. If you look at the definition of Map intereface using source available in JDK (beyond 1.5 ), it will be like
public interface Map<K,V> {
So if you use the Map without generics that should work with latest code. Thats why the java type erasure is brought in. When you use generics compiler checks whether you use all you type properly or not. If something is wrong you get an error at compile time and you need not wait until run time and blow up your production.

Consequences of Type Erasures

A java class with parametrized type cannot be instantiated as it requires a call to constructor. At run-time the type is not available because of type erasure and the instantiation cannot be done.
T instantiateElementType(List<T> arg)
{
  return new T(); //causes a compilation error
}
Because of type erasure, at run-time you will not be able to find out what was the predefined type. There are hacks available using Reflection, but it is not guaranteed that it will work in all cases. It is also not a formal way.
There is lots of discussions on whether you need type erasure or is it implemented in a good way is going around. Leave that aside. If you use java, its better to use generics as much as possible. Advantage you get in using generics is type safety and clarity in your code. Though type erasure is good or bad, better know about it. Because it is the one that translates your generic java code to byte code.


0 comments:

Post a Comment