List<Double> or List<Float> cannot be assigned to List<Number> because, List<Double> isn't extend List<Number>.
Upper-bound
We can add object of Double type or its sub types to List<Double>.
Same way we can add Number or its sub types (e.g. Double, Float, Integer) to List<Number> but, we cannot assign dblList to numList. Why?
The reason is that we can add any sub type of Number to numList and numList is just a reference of dblList so that sub type would actually be added in dblList, if that sub-type is Integer or Float than it is problem.
Now if we do this...
It is used to get data from container, not to add data to container.
When we do like this..
Lower-bound
Lower-bond is used to add data to container but when we try to get data from container it returns us Object.
Let's see why.
We only allowed to add Number and its sub-types to numList then, what's use of it?
We can pass List<Object>, List<Serializable> to method which accepts List<? super Number>.
That way once the method finishes adding values to container we have a container to perform specific operation on.
It can be any super type of list as shown in above case so it always resolves to base class Object.
List<Double> dblList = new ArrayList<>(); List<Number> numList = dblList; //illegalTo do that we need to use upper-bound wild card.
List<Double> dblList = new ArrayList<>(); List<? extends Number> numList = dblList;Same way List<Number> isn't extend List<Object> so, List<Object> cannot be assigned to List<Number>
List<Object> objList = new ArrayList<>(); List<Number> numList = objList; //illegalTo do that we need to use lower-bound wild card
List<Object> objList = new ArrayList<>(); List<? super Number> numList = objList;
Upper-bound
We can add object of Double type or its sub types to List<Double>.
Same way we can add Number or its sub types (e.g. Double, Float, Integer) to List<Number> but, we cannot assign dblList to numList. Why?
The reason is that we can add any sub type of Number to numList and numList is just a reference of dblList so that sub type would actually be added in dblList, if that sub-type is Integer or Float than it is problem.
List<Number> numList = dblList; //Suppose this is possible then numList.add(new Integer(1)); // this is not solving purpose of List<Double> numList.add(new Float(3.2)); //same as aboveThat's why above assignment made illegal by java compiler.
Now if we do this...
List<? extends Number> numList = dblList; // Legalthen also above scenario would be happenned... so, compiler made illegal to accept value in any of the method where type declared with <? extends SomeClass>
class MyContainer<T> { ... public void accept(T value) { ... } ... }If we declare reference of MyContainer<? extends Number> then any method like "accept" which accepts "T" as parameter is illegal on that reference.
numList.add(new Integer(1)); //illegal numList.add(new Double(2.34)); //illegal!So, what's the use of upper-bound wild card?
It is used to get data from container, not to add data to container.
When we do like this..
Number value = numList.get(0);We are sure here that at least we get Number from numList because it has Number or sub-types of it but, if compiler allow to call add on numList reference then below situation can be occurred.
List<? extends Number> numList = dblList; numList.add(new Integer(4)); //This is not logical, so compiler don't want to arise this situation
Lower-bound
Lower-bond is used to add data to container but when we try to get data from container it returns us Object.
Let's see why.
List<Object> objList = new ArrayList<>(); List<? super Number> numList = objList;Here it doesn't mean we can add Number or any of its super type to container. No.
We only allowed to add Number and its sub-types to numList then, what's use of it?
We can pass List<Object>, List<Serializable> to method which accepts List<? super Number>.
That way once the method finishes adding values to container we have a container to perform specific operation on.
public void addValues(List<? super Number> numList) { for(int i = 0; i < 10; i ++) { numList.add(i); } } public void customSerializationOfList(List<Serializable> serList) { for(Serializable ser : serList) { ... ObjectOutputStream oos = ... oos.writeObject(ser); ... } } public void customPrintingOfList(List<Object> objList) { for(Object obj : objList) { System.out.println("**** Obj: "+obj.toString()+" ****"); } } public void operateForObjectList() { List<Object> objList = new ArrayList<>(); addValues(objList); customPrintingOfList(objList); } public void operateForSerializableList() { List<Serializable> serList = new ArrayList<>(); addValues(serList); customSerializationOfList(serList); }Here, our purpose is to use general method customSerializationOfList which can be used from any other part of application with List<String>, List<Color> etc. Here, if we try to get value from numList it always returns Object type because, it doesn't know which super type of Number the container is of.
Unbounded
Unbounded type is unknown type with no binding information.
List<?> unList = new ArrayList<>();Any kind of List can be assigned to unList reference. We cannot add value to container pointed by unList type of reference and if we try to get value from unList type of reference it always resolves to Object.
This is used when we want value of container just to be Object but we cannot declare it as List<Object> specifically
public List<? super Number> getList() { ... } public void doSomethingOnList(List<?> objList) { for(Object obj : objList) { //do something on each obj } } List<?> unList = getList(); doSomethingOnList(unList);We can pass reference of List<Object> to doSomethingOnList method
List<Object> objList = new ArrayList<>(); doSomethingOnList(objList);but,
List<Object> objList = getList(); //illegal
Comments
Post a Comment