Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

On Java generics lower bound usage: ? super T [duplicate]

Tags:

java

generics

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?

like image 347
user496934 Avatar asked Oct 29 '17 06:10

user496934


2 Answers

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:

  • Explicit intent: ? super T more explicitly shows what types dest should take.
  • Modularity: you don't need to look at the type constraints on src at all to know what types dest can take.
  • Producer Extends, Consumer Super (PECS): a producer parameter ("in" below) should use 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 a copy method with two arguments: copy(src, dest). The src 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 the copy example, copy(src, dest), the dest 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.
like image 107
River Avatar answered Oct 22 '22 05:10

River


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);
like image 42
Eran Avatar answered Oct 22 '22 04:10

Eran