Tuesday, February 23, 2010

Generics and Polymorphism

List<Object> li = new ArrayList<Number>();//1

Why this will give compilation error? Number is sub class of Object, isn't this the way polymorphism works in java.

Let's investigate the problem raised if compiler allows it. If compiler accepts list of type object to refer list of any subclass of object then same will be true for adding any subtype of object to li, as mentioned below in line 2

li.add("SHIV"); //2


In essence, if compiler doesn't stop it at line 1 while assigning, it will never be in position to stop you from putting string into Number list. So correct way will be

List<Object> li = new ArrayLLIst<Object>();

i.e. List<T> li = new ArrayList<T>(); implies T in both side should be exactly same.

But this look like a serious restriction, how to get away with this(I mean how to achieve polymorphism in generics)? Java comes with wild card to solve these issue to some extent.

List<?> li = new ArrayList<Number>();//3
List<? extends Object> li = new ArrayList<Number>();//4
List<? super Boolean> li = new ArrayList<Number>();//5

In line 3 li can be assigned to ArrayList on any type, n line 4 li can be assigned to any type which extends object and line 5 can refer to any type super class of Boolean. It's evident from the above examples that wild card (?) get us polymorphism in case of generics. But polymorphism in generics comes with some restrictions. Let's discuss them.
List<?> li = new ArrayList<Number>();

li can be assigned to any type but nothing can be added to li. Because compiler will be aware of only reference type, and that is wild card(not a type).

List <? extends Number> li= new ArrayList<Boolean>();

Here li can be used to refer any object that extends Number. What about adding objects to li? Think carefully and answer. If your answer is any object extends Number can be added, then you are wrong. Actually you cannot add object of any type to li. Because here again compiler doesn't know which type exactly li is referring to. Without the restriction you may end up creating list of Boolean and add Number to it.

List <? super Number> li = new ArrayList<Number>();
What about this, as you might have guessed that li can refer to Number or any super class of it. But the big deal will always be about adding element to li. Good news is that, this is only combination with wild card where elements can be added. Compiler is sure that type of li will be either Number or any super class of Number. So if you add Number or sub class of it, it's perfectly fine.

Lets summarize it....


What li can refer to
What can be added to li

List<T> li = new ArrayList<T> ()
li can refer only ArryList of type T T or any sub class of T can be added to li

List<?> li = new ArrayList<T> ()
li can refer any type Nothing can be added to li

List<? extends T> li = new ArrayList<T> ()
li can refer ArrayList of type T or any sub type of T Nothing can be added to li

List<? super T> li = new ArryList<T>()
li can refer ArrayList of type T or any supertype of T T or any sub type of T can be added to li

1 comment: