Let's consider a small example on Generics:
In the above example, "st" is a reference variable and and it's reference type is
List<? super String>. What does it mean? Yes, it says "ANY super class of String". But keep in mind that it is not saying that you can pass any super type of String to the
add(-) method of
st. The only thing what it is saying is that the VALUE object for this variable (initialization value) CAN be either String or a super-type of it. Let's see a simple example.
Given the statement below:
According to the generic declaration shown above, you can INSTANTIATE the variable
st, with any super type of String, as the
generic-argument. For an example:
All of the above instantiations are correct, because java.lang.Object and java.io.Serializable are super types of String, (and String is the same type, so it also can be used).
Now the question is, what can you pass to the
add(-) method?
Think about it. The compiler don't know, what will be the instantiation generic type (right side) at the compile time. It can be either String, Object, or Serializable, .... as I shown above.
The key point you have to keep in mind again and again, is, the COMPILER don't know about the INSTANTIATION generic type exactly. The compiler know that it can be ANY super class of String. But it does not know what it is exactly. Because the
Java compilation process always deals with the reference type only. (Think about it. You can specify so many instantiations for a one reference variable within a loop, or in a nested if condition. Thus the COMPILER cannot track them).
The argument you passed to the
st.add(-) method, MUST be same or a super class of the INSTANTIATION generic type. But as I described above, the compiler doesn't know, about the INSTANTIATION Generic type exactly. It knows about the reference generic type only (i.e.
List<? super String>).
Now, if you attempt to pass an "Object" instance to the
add(-) method, the compiler will not permit you to do so. Because as I said, the compiler doesn't know about the instantiation generic type, and the compiler knows that passing an "Object" instance MAY BE a problem at runtime if the instantiation generic-type is NOT Object. In another way, the compiler knows that passing a java.io.Serializable (implemented) instance MAY BE a problem at runtime if the instantiation generic-type is NOT either Serializable or a super-type of it. In these cases, the compiler gives an error, as I shown in the first code.
But, what if we are passing a "String" instance to the
add(-) method? In this case, the compiler know that it is IMPOSSIBLE TO BE a problem at runtime, even if the instantiation generic type is either String, Object, or Serializable. Because Object and Serializable are super types of String. In this case, it will compile successfully.
Also, imagine that
SubString is a sub class of String (even though it is not possible to extend from String, as String is a final class), In this case you can pass a
SubString instance to the
add(-) method, by applying the above theory.
Now, as a summary, we can say, if the generic type of the REFERENCE is
List<? super X>, we can pass either X or any SUB class of the X to the
add(-) method. But you can NOT pass a SUPER class of X.
Can you try to apply the above theory, when the REFERENCE generic type is
List<? extends Number>