I am trying to understand the usage of lower bound wildcards in some depth. I am trying to write a generic method copy
which copies the contents of one List
to another. I came up with this method signature:
<T> void copy(List<T> dest, List<? extends T> src)
I think this signature is comprehensive to address all scenarios. However, I see that in the Java Collections class the method signature is like this:
<T> void copy(List<? super T> dest, List<? extends T> src)
I do not understand why they use List<? super T> dest
instead of just List<T> dest
. Is there some extra flexibility with their signature?
There is no practical difference without explicit type witnesses.
Without specifying a type witness as done by Eran, there are no differences in flexibility between the two methods.
Essentially, the use of ? super T
over T
is only a stylistic difference, however it is better practice, as can be seen by applying a number of principles of good code:
? super T
more explicitly shows what types dest
should take.src
at all to know what types dest
can take.extends
while a consumer parameter ("out" below) should use the super
keyword.Using ? super T
is also recommended by the Java tutorials (they even use a copy
function):
For purposes of this discussion, it is helpful to think of variables as providing one of two functions:
An "In" Variable
An "in" variable serves up data to the code. Imagine acopy
method with two arguments:copy(src, dest)
. Thesrc
argument provides the data to be copied, so it is the "in" parameter.An "Out" Variable
An "out" variable holds data for use elsewhere. In thecopy
example,copy(src, dest)
, thedest
argument accepts data, so it is the "out" parameter.You can use the "in" and "out" principle when deciding whether to use a wildcard and what type of wildcard is appropriate. The following list provides the guidelines to follow:
Wildcard Guidelines:
- An "in" variable is defined with an upper bounded wildcard, using the
extends
keyword.- An "out" variable is defined with a lower bounded wildcard, using the
super
keyword.
Here's an example:
The following snippet passes compilation with the signature <T> void copy(List<? super T> dest, List<? extends T> src)
but doesn't work with the signature <T> void copy(List<T> dest, List<? extends T> src)
:
YourClass obj = new YourClass ();
List<HashMap<String,String>> lhm = new ArrayList<>();
List<Map<String,String>> lm = new ArrayList<>();
obj.<HashMap<String,String>>copy (lm,lhm);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With