Adding elements to this type of list is not possible as the wildcard declaration of List<? extends Number> ml
means that the variable ml
may contain any family value Number
, instead of any value of a specific type. See the equivalent assignments below that would be allowed:
List<? extends Number> foo3 = new ArrayList<Number>; // Number "extends" Number
List<? extends Number> foo3 = new ArrayList<Integer>; // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>; // Double extends Number
That said, the type of object you can add to the List foo3
which would be valid after any of the above ArrayList
would bump into the problems below:
- You can’t add one
Integer
because foo3
could be pointing to a List<Double>
.
- You can’t add one
Double
because foo3
could be pointing to a List<Integer>
.
- You can’t add one
Number
because foo3
could be pointing to a List<Integer>
.
Therefore:
You cannot add any object to List<? extends T>
because you can’t guarantee that List
is actually pointing to this type, so you cannot guarantee that the object to be added is allowed in that list. The only "guarantee" you have is that you can only read this list and you will get one T
subclass of T
.
The reverse logic applies to the use of super
, according to the assignments below, which are also valid:
List<? super Number> foo3 = new ArrayList<Number>; // Number é "superclasse" de Number
List<? super Number> foo3 = new ArrayList<Object>; // Object é "superclasse" de Number
About List<? super T>
, the following conclusion can be reached:
You can’t read the type T
specific (for example Number
) from List<? super T>
because you can’t guarantee what kind of List
is really pointing to it. The only "guarantee" you have is that you are able to add a type value T
(or any subclass of T
) without violating the integrity of the list being pointed out.
The statement to the left(List<? extends Number> foo3
) sets the data type that can be assigned to your Arraylists on the right(= new ArrayList<Integer>();
), and not the data type that can be added to the created list.
Translated and adapted from this reply from Soen
References for reading:
Now I understand what is covariance and contravariance. I just don’t understand why it gives compilation error when I try to add a type that extends Number.
– user2509556
I didn’t get that either,
ml.get(0)
returns aNumber
, but when I tested doml.add(ml.get(0));
also gave compilation error! After all, what kind of objects a list "List<? extends Number>" is able to receive? You can help us @Articuno? :) - Obs.: when doingList<Number> ml = new Vector<Number>();
(unusedextends
) the list can receiveInteger
andDouble
normally.– Douglas
Number
is an abstract class representing a collection of types, you cannot define a list that accepts number types and on the right hand side define the vector for integer type, there is no way List ensures that the number type is integer, since number is an inherited supertype of several numeric subtypes like Double, Float. This list becomes read only, it is not possible to add anything as it is not possible to guarantee that the type of number adding is the same informed in the assignment– user28595
What if I make a list? extends Number> ml=new Vector<Number>(); Why can’t I also add its subtypes, giving compilation error? but when I do List<? super Number> ml=new Vector<Number>(); I can add Double Integer, etc.?
– user2509556
My explanation in the previous comment is valid for all cases where you use
List<? extends Number>
regardless of what you declare on the right side.– user28595
What the compiler takes into account is the reference variable.
– user2509556
If you stop to notice, the problem that occurs in
List<? super Number>
is exactly the opposite that occurs withList<? extends Number>
, Because the problem here is the exact opposite of what I explained. Once again reinforcement: you need to read all the answers of the two links and understand the concept of covariance and contravariance to understand this problem.– user28595
@I would if I did "
List<? extends Number> ml = new Vector<Integer>();
" and then did "ml.add(new Double(7d));
" I would expect to receive a Classcastexception at runtime, but from what I understood from what you said, the Compiler will not allow me to add anything to the "ml" list to avoid this type of Exception. That means that at no time will the Compiler allow me to do "ml.add(...)
"?, there is absolutely nothing I can pass as parameter that the compiler accepts?– Douglas
@Douglas, you see, who defines the type is the statement on the left. So, this statement says that we will create a list that accepts only subtypes of Number, it limits only what we start on the left side and not what we will add to the created list. When adding something to this list, there is no way to guarantee that that object is allowed in the list, because a
Double
would be a type allowed in that list because it inherits from Number, but the compiler has no way to verify that the list does not allow Double, so it does not allow the addition.– user28595
I modified the question so that it is no longer duplicate and more specific the doubt, see if it is ok, anything wrong, let me know to undo the editing.
– user28595
Possible duplicate of What is the purpose of the super command when used in the parameter declaration of a method?
– Tiago S
@Tiagos I disagree with this being duplicate. The other question talks about the
? super
and not about the? extends
. The answer even talks a little about the? extends
, but does not go into more detail and does not talk about the problem outlined in this question.– Victor Stafusa