Skip to main content

Generics wild card in java

List<Double> or List<Float> cannot be assigned to List<Number> because, List<Double> isn't extend List<Number>.
List<Double> dblList = new ArrayList<>();
List<Number> numList = dblList; //illegal
To 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; //illegal
To 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 above
That's why above assignment made illegal by java compiler.
Now if we do this...
List<? extends Number> numList = dblList; // Legal
then 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. 
It can be any super type of list as shown in above case so it always resolves to base class Object.

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

Popular posts from this blog

Basics of quantum computing: change of basis

Computing requires classical bits, which can hold a value of 0 or 1. Quantum computing gets benefit from superposition of quantum bit (qubit). Qubit is a representation of state of quantum object (electron, proton, photon, etc). The qubit holds a value between 0 and 1 while it is in superposition state. Superposition means the qubit possesses multiple values at the same time so we can harness its power for parallel computing. Once we try to measure the value it can be collapsed into either 0 or 1 based on probability. (Observer collapses wave function simply by observing.) Using bloch sphere, we can represent qubit physically. (The bloch sphere is a physical model to represent a spin state of qubit) A state vector can point to any direction from the center of the sphere. If a vector points to Z+ and Z-, it represents 0 and 1 state respectively. All other vectors represent superposition state in a Z basis. Now, if a vector points to X+, X-, Y+, Y-, all are at a 90-degree angle from ...

A deep understanding of neural network

Basics Neural network is a mathematical function to solve some programming problems which is almost impossible to be solved with conventional programming. Neural network consist of neurons and weights. Neurons are made up with activation function and holds output of the function called activation value. Weights are just values which connects one neuron to another. Neurons are grouped and forms a layer. Each layer is connected with other layer by weights. There are three kind of layers; input layer, hidden layer and output layer. Any neural network contains at least one hidden layer, though there might be more than one hidden layers are possible. Input layers accepts input, calculate activation values for next hidden layer, the next layer does same process and pass result to next of it. This goes on until output layer is reached.  Each layer calculates Z values using weight and activation. Using Z values activation of next layer is calculated. Once we get activation of output laye...

`this` keyword in javascript

this keyword used to reference current object in javascript. There are two scenario where current object is determined differently. * Calling object represented by `this` in function. * Arrow function can reference object where the function defined. To demonstrate the above scenarios we shall take some examples. Suppose, var x = 10; (function() {    console.log(this.x); })() // 10 (() => {    console.log(this.x); })() // 10 There are two self executing functions both resulted in "10". At first look it seems behaving same, but there is basic deference what we going to see. const xObj = {     value: 10,     getValue: () => {         return this.value;     } }; const yObj = {     value: 10,     getValue: function () {         return this.value;     } }; xObj.getValue(); // undefined yObj.getValue(); // 10 Why undefined for `xO...