The <? super T>
within <T extends Juicy<? super T>>
is there so that RedOrange
, which is a subclass of Juicy<Orange>
can be within its bound.
Imagine without the <? super T>
first:
public <T extends Juicy<T>> List<Juice<T>> squeeze(List<T> fruits) {...
Now T
must be a Juicy<T>
. The class Orange
is a Juicy<T>
, it's a Juicy<Orange>
. But the class RedOrange
is not a Juicy<T>
. It's not a Juicy<RedOrange>
; it's a Juicy<Orange>
. So when we attempt to call squeeze
:
List<RedOrange> redOranges = new ArrayList<RedOrange>();
List<Juice<RedOrange>> juices = squeeze(redOranges);
we get the following compiler error:
Inferred type 'RedOrange' for type parameter 'T' is not within its bound; should implement 'Juicy<RedOrange>'.
If we place the <? super T>
, that allows the type parameter for Juicy
to be a superclass of T
. This allows RedOrange
to be used, because it's a Juicy<Orange>
, and Orange
is a superclass to RedOrange
.
public <T extends Juicy<? super T>> List<Juice<T>> squeeze(List<T> fruits) {...
Now the call to squeeze
above compiles.
EDIT
But what if we want to squeeze
a List<Juice<Orange>>
from a List<RedOrange>
? It got a little tricky, but I found a solution:
We need a second type parameter to match Orange
in the squeeze
method:
public <S extends Juicy<S>, T extends Juicy<S>> List<Juice<S>> squeeze(List<T> fruits)
Here, S
represents Orange
, so that we can return List<Juice<Orange>>
. Now we can say
List<RedOrange> redOranges = new ArrayList<RedOrange>();
List<Juice<Orange>> juices = squeeze(redOranges);