I have a List which is declared like this :
List<? extends Number> foo3 = new ArrayList<Integer>();
I tried to add 3 to foo3. However I get an error message like this:
The method add(capture#1-of ? extends Number) in the type List<capture#1-of ?
extends Number> is not applicable for the arguments (ExtendsNumber)
You could do this instead:
where extend list from 'Object' , you can use list.add and when want use list.get only need to cast Object to your Object;
It has been confusing to me even though I read answers here, until I found the comment by Pavel Minaev:
After this I was able to understand BertF awesome explanation. List < ? extends Number > means ? could be of any type extending Number(Integer, Double, etc) and its not clearified in declaration ( List < ? extends Number > list ) that which of them it is, so when u wanna use add method its not known if the input is of the same type or not; what is the type at all?
So the elements of List < ? extends Number > could only be set when constructing.
Also note this: When we're using templates we are telling the compiler what type we're messing with. T for example holds that type for us, but not ? does the same
I gotta say.. This is one of the dirty ones to explain/learn
"List '<' ? extends Number> is actually an upper bound wildcard !
The upper-bounded wildcard says that any class that extends Number or Number itself can be used as the formal parameter type: The problem stems from the fact that Java doesn’t know what type List really is. It has to be an EXACT and UNIQUE Type. I hope it helps :)
Sorry, but you can't.
The wildcard declaration of
List<? extends Number> foo3
means that the variablefoo3
can hold any value from a family of types (rather than any value of a specific type). It means that any of these are legal assignments:So, given this, what type of object could you add to
List foo3
that would be legal after any of the above possibleArrayList
assignments:Integer
becausefoo3
could be pointing at aList<Double>
.Double
becausefoo3
could be pointing at aList<Integer>
.Number
becausefoo3
could be pointing at aList<Integer>
.You can't add any object to
List<? extends T>
because you can't guarantee what kind ofList
it is really pointing to, so you can't guarantee that the object is allowed in thatList
. The only "guarantee" is that you can only read from it and you'll get aT
or subclass ofT
.The reverse logic applies to
super
, e.g.List<? super T>
. These are legal:You can't read the specific type T (e.g.
Number
) fromList<? super T>
because you can't guarantee what kind ofList
it is really pointing to. The only "guarantee" you have is you are able to add a value of typeT
(or any subclass ofT
) without violating the integrity of the list being pointed to.The perfect example of this is the signature for
Collections.copy()
:Notice how the
src
list declaration usesextends
to allow me to pass any List from a family of related List types and still guarantee it will produce values of type T or subclasses of T. But you cannot add to thesrc
list.The
dest
list declaration usessuper
to allow me to pass any List from a family of related List types and still guarantee I can write a value of a specific type T to that list. But it cannot be guaranteed to read the values of specific type T if I read from the list.So now, thanks to generics wildcards, I can do any of these calls with that single method:
Consider this confusing and very wide code to exercise your brain. The commented out lines are illegal and the reason why is stated to the extreme right of the line (need to scroll to see some of them):
You can't (without unsafe casts). You can only read from them.
The problem is that you don't know what exactly the list is a list of. It could be a list of any subclass of Number, so when you try to put an element into it, you don't know that the element actually fits into the list.
For example the List might be a list of
Byte
s, so it would be an error to put aFloat
into it.