From Programming Languages: Principles and Paradigms
By Maurizio Gabbrielli, Simone Martini
The bound mechanism for type variables is fairly sophisticated and
flexible. In particular, a type variable can appear in its own bound.
We restrict ourselves to a single example of this case, and we refer
the reader to the bibliography for a deeper discussion.The elements of a class are comparable if the class implements the
Comparable
interface. We want to define a method which, given a list
of elements of generic type as its argument, returns the maximum
element of this list. What is the signature we can give to this max
method? A first attempt is:public static <T extends Comparable<T>> T max(List<T> list)
This expresses the fact that the elements of the list must be
comparable with elements of the same type. We now try to usemax
. We
have a typeFoo
which allows us to compare objects:class Foo implements Comparable<Object>{...} List<Foo> cf = ....;
We now invoke
max(cf)
: each element incf
(is aFoo
and
therefore) is comparable with any object, in particular with every
Foo
. But the compiler signals an error, becauseFoo
does not
implementComparable<Foo>
. In reality it is sufficient thatFoo
is
comparable with one of its own supertypes:public static <T extends Comparable<? super T>> T max(List<T> list)
Now, under the same conditions as before,
Max(cf)
is correct because
Foo
implementsComparable<Object>
.
-
I assume that
? super T
means any supertype ofT
.Since
Object
is a supertype ofT
, does the following signature
ofmax
work?public static <T extends Comparable<Object>> T max(List<T> list)
If yes, why not use it instead the last one in the quote?
- This is an example involving
Comparable
interface. What is the
general problem that we can use the method in the quote to solve?
If we had:
public static <T extends Comparable<Object>>
T max(List<T> list)
It would have worked with
class Foo implements Comparable<Object>{...}
List<Foo> cf = ....;
But not with
class Bar implements Comparable<Bar>{...}
List<Bar> cf = ....;
Their first max
signature demands that T
can be compared with T
– therefore it can not work on a List
of Foo
s, because Foo
s can be compared with Object
. Your max
signature demands that T
can be compared with Object
, therefore it can not work on a List
of Bar
s, because Bar
can only be compared with another Bar
.
Their second max
version is needed to work on both List<Foo>
and List<Bar>
. It says: “give me a list of something that can compare against other objects of it’s type, but if it has a wider comparison method, that also accepts other types, that would be OK – as long as it can accept it’s own type.“.
So, a list of Baz implements Comparable<Foo>
is out of the question, because, because a Baz
can not be compared against itself(Baz is not a subclass of
Foo`).
Basically, the general problem solved by this method is that something in a generic may work with a subclass/superclass of the generic parameter, because you are only upcast from/to it. You use ? super T
/? extends T
to encode this in the signature, so that the generic may be used with a wider variety of types.