Tuesday, 31 October 2017

What is the problem with type erasure?

Type Erasure is a process, where Java Compiler replaces type with its first bound if the type parameter is bounded, or Object if the type parameter is unbounded.

Let me explain with an example,

Box.java
public class Box<T> {

    private T data;

    public Box(T data) {
        this.data = data;
    }

    public T getData() { return data; }

}

“T” is unbounded type in Box class. So Java Compiler replaces Every Occurrence of T with Object. After compilation, above class will be converted like below.


Box.java
public class Box {

    private Object data;

    public Box(Object data) {
        this.data = data;
    }

    public Object getData() { return data; }

}

let us see one more Example with bounded type.


Box.java
public class Box<T extends Integer> {

    private T data;

    public Box(T data) {
        this.data = data;
    }

    public T getData() { return data; }

}


After type Erasure, Type Parameter “T” will be converted to Integer.
Box.java
public class Box{

    private Integer data;

    public Box(Integer data) {
        this.data = data;
    }

    public Integer getData() { return data; }

}


What is the problem with type erasure?
a.   Since type erasure erase the type information, there is no way to get the type information at run time.
b.   Because of the type erasure, you may add one type of object to collection of other type. This makes the application fails at run time.
MyCollection.java
package utils;

import java.util.ArrayList;
import java.util.List;

public class MyCollection<T> {

 private List<T> myList = new ArrayList<> ();
 
 @SuppressWarnings("unchecked")
 public void addToList(Object obj){
  myList.add((T) obj);
 }
 
 public void printCollection(){
  for(T obj : myList){
   System.out.println(obj);
  }
 }
}
Test.java
package utils;

public class Test {

 public static void main(String args[]) throws CloneNotSupportedException {
  MyCollection<Integer> collection = new MyCollection<>();

  collection.addToList("krishna");
  collection.addToList(1234);
  collection.addToList(123.456);

  collection.printCollection();
 }
}

Even though I defined the collection myList is of type Integer, I can able to add all types of objects to the collection. Compiler is unable to catch this kind of problems.

How to identify above kind of problems?
Before adding the elements to the collection, we can cast the elements using ‘cast’ method of java.lang.Class. ‘cast’ method throws ‘ClassCastException’, if it is unable to cast the object to given type.

Find the below working application.

MyCollecton.java
package utils;

import java.util.ArrayList;
import java.util.List;

public class MyCollection<T> {

 private List<T> myList = new ArrayList<>();
 private final Class<T> myClass;

 public MyCollection(Class<T> myClass) {
  this.myClass = myClass;
 }

 public void addToList(Object obj) {
  myList.add(myClass.cast(obj));
 }

 public void printCollection() {
  for (T obj : myList) {
   System.out.println(obj);
  }
 }
}

Test.java
package utils;

public class Test {

 public static void main(String args[]) throws CloneNotSupportedException {
  MyCollection<Integer> collection = new MyCollection<>(Integer.class);

  collection.addToList("krishna");
  collection.addToList(1234);
  collection.addToList(123.456);

  collection.printCollection();
 }
}


When you ran above program, you will end up in below error.

Exception in thread "main" java.lang.ClassCastException: Cannot cast java.lang.String to java.lang.Integer
    at java.lang.Class.cast(Unknown Source)
    at utils.MyCollection.addToList(MyCollection.java:16)
    at utils.Test.main(Test.java:8)

You may like

No comments:

Post a Comment