The Collections.fill method has the following header:
public static <T> void fill(List<? super T> list, T obj)
Why is the wildcard necessary? The following header seems to work just as well:
public static <T> void fill(List<T> list, T obj)
I cannot see a reason why the wildcard is needed; code such as the following works with the second header as well as the first:
List<Number> nums = new ArrayList<>();
Integer i = 43;
fill(nums, i); //fill method written using second header
My question is: For what specific call of fill would the first header work but not the second? And if there is no such call, why include the wildcard? In this case, the wildcard does not make the method more concise nor add to readability (in my opinion).
This is a really good question and the simple answer was guessed already:
The above statement derives from the principle that: if there is a such type
Xso thatXis a supertype ofTthenList<X>is a supertype ofList<? super T>because of type contravariance. Since we can always find suchX(at the worst case it's theObjectclass) - the compiler can infer a suitableList<X>argument type given either form offill.So, knowing that fact we can interfere with the compiler and infer the type ourselves using "type witness" so the code breaks:
This is all of course purely theoretical and nobody in their right mind would use the type argument there.
HOWEVER
While answering the question "What is the benefit of using wildcards here?" we yet considered only one side of the equation - us, consumers of the method and our experience but not library developers.
Hence this question is somewhat similar to why
Collections.enumeration(final Collection<T> c)is declared the way it is and notenumeration(Collection<T> c)asfinalseems superfluous for the end-user.We can speculate here about the real intention, but I can give a few subjective reasons:
List<? super T>(as well asfinalforenumeration) immediately disambiguates the code that tiny bit more and for the<? super T>specifically - it useful to show that only partial knowledge about the type parameter is required and thelistcannot be used to produce values of T, but only to consume them. Quote:Now let's try make up some hypothetical "improvements" to see what I mean (I'll call the form of
fillthat usesList<T>asfillNew):#1 The decision is to make method to return the
objvalue (used to fill up the list) back:The updated method would work just fine for
fillsignature, but forfillNew- the inferred return type now isn't that obvious:#2 The decision to add an overloaded version of
fillthat is 10x more performant in cases whenTisComparable<T>:To sum up - the current signature of
fillis more flexible/descriptive in my opinion for all parties (developers and library designers)