I have read many sources about wildcards and Java generics. Even though I have seen many explanations and answers, none of them seems correct.
The question is very simple: Do wilcards in Java generics increase flexibility?
My understand is "No". Wildcards in Java generics (wilcards) actually decrease flexibility.
When I first looked at and used Java generics mechanism, I rarely/never used wildcards. Very often I saw and used the form <T> abc(T xt)
. One day I got a test question about super
and later I started looking at wildcards more closely.
Many sources and in particular: Effective Java 2nd gives an example as follows to show how wildcards increase flexibility.
public class Stack<E> {
...
public void pushAll(List<E> list) {...}
...
}
The books goes on and says that since we should be able to use List
of anything extending E
as argument to pushAll(List<E> list)
, this is not flexible enough. Therefore, the book suggest changing the signature of the method to pushAll(List<? extends E> list)
. Now if E
is Number
then we can even use List<Integer>
as argument for pushAll(List<? extends Number> list)
. And that we have increased flexibility (of the API).
My understanding is that the other solution is not to use wildcards but to use the regular typing. In that case, if we change the method signature to
public <T extends E> void pushAll(List<T> list)
we will achieve the same thing that the wildcard version wants to achieve.
And now in the body of the method, not only we can read from list
, we can also write into it. If we use the the wildcard version, we cannot write into that list any value other than null
. So in this view, wildcards actually decrease flexibility, not increase.
All in all, it looks to me that wildcards are actually used to decrease flexibility so that <? extends X>
discourages people from writing into the object while <? super X>
discourages people from reading the object (try it and you will get only Object
as type of the returned value). The following example illustrates the <? super X>
case.
public void popAll(List<? super E> list) {
Object x = list.get(0) // Only get Object as type here, reading is discouraged
}
We can change the signature to public <T extends E> void popAll(List<T> list)
.
Now we can write or read as we want. There is no restriction.
So to sum up: All usages of wildcards can be substituted by typed parameter in the manner of <T extends E>
(so there can be no need for the keyword super
) . Using wildcards, we lose flexibility in the ability to both read and write into the object. Therefore, wildcards decrease flexibility.
Is it therefore true that wildcards in Java actually decrease flexibility? If not, how is my reasoning flawed?
[My question is flawed as per missing the cases as mentioned by @Doval in the comment under his answer.]
List<List<T>>
is not as permissive asList<List<?>>
. en.wikipedia.org/wiki/…List<List<?>>
is not flexible (cannot insert other thannull
) as<E extends Object> List<List<E>>
. The latter one is equally permissive.List<List<?>>
is not flexible" you've got it the wrong way around. The more restrictions you put on the implementer, the more freedom you're giving the caller. The fact that the implementer can't make any assumptions about the contents of the innerList
s means the caller can give them any list-of-lists. That aside, I don't know where you're getting this idea that you can substitute? super E
withT extends E
.? super E
forT super E
, but not forT extends E
.super
!=extends
. That is my point.