Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bounded generic method with 'super' type

As per a literature I read,we have juicy fruits implementign the following interface:

public interface Juicy<T> {
    Juice<T> squeeze();
}

Using bounded type variables, following method would taks a bunch of fruits and squeeze them all:

<T extends Juicy<T>> List<Juice<T>> squeeze(List<T> fruits);

Now we need lower siblings as below to work too:

class Orange extends Fruit implements Juicy<Orange>;
class RedOrange extends Orange;

So I would expect the method to look as follows:

<T extends Juicy<T>> List<Juice<? super T>> squeeze(List<? extends T> fruits);

Instead I find the method signature to be as below:

<**T extends Juicy<? super T>>** List<Juice<? super T>> squeezeSuperExtends(List<? extends T> fruits);

What explains this difference?

like image 253
IUnknown Avatar asked May 07 '13 17:05

IUnknown


People also ask

How do you provide a parametrized type for a generic?

In order to use a generic type we must provide one type argument per type parameter that was declared for the generic type. The type argument list is a comma separated list that is delimited by angle brackets and follows the type name. The result is a so-called parameterized type.

What is bounded generic type?

If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class. These are known as bounded-types in generics in Java.

Can generics take multiple type parameters?

Multiple parametersYou can also use more than one type parameter in generics in Java, you just need to pass specify another type parameter in the angle brackets separated by comma.

Can a parameterized type have several bounds?

A type parameter can have multiple bounds.


1 Answers

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);
like image 97
rgettman Avatar answered Oct 05 '22 05:10

rgettman