The only reason I can find to have <T extends Object & Comparable<? super T>
, as opposed to T extends Comparable<? super T>
, is for backwards compatibility when generifying a method.
According to Angelika Langer's Java Generics FAQ:
Occasionally, one must pay attention to the fact that a generification might change the signature of some methods in the byte code. Changing the signature will break existing code that cannot be recompiled and relies on the binary compatibility of the old and new version of the .class file.
In this case, Java's own Collections.max
used to return Object
before 1.5, the arrival of generics. When generified, this method could be declared without extends Object
, and it would work correctly in isolation.
public static <T extends Comparable<? super T>> T max(Collection <? extends T> coll)
However, the erasure of this method, for bytecode purposes, has this method returning Comparable
, instead of Object
, which is a backwards incompatibility.
To resolve this, extends Object
was inserted as the first bound, so that the erasure of the return type of this method would remain Object
.
This resolved the backwards incompatibility issue for Java generics in 1.5.
However, the question in the tutorial stated:
Write a generic method to find the maximal element in the range [begin, end)
of a list.
You are writing your own new method, so there is no backwards compatibility to maintain yet. The extends Object
in the answer to this tutorial question is unnecessary.
In addition
In the bytecode (javap -c Algorithm.class
), all types undergo type erasure, even the local variable maxElem
.
public static <T extends java.lang.Comparable<? super T>> T max(java.util.List<? extends T>, int, int);
Code:
0: aload_0
1: iload_1
2: invokeinterface #2, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
The get
method has returned an Object
. Then how does it invoke compareTo
in Comparable
?
7: astore_3
8: iinc 1, 1
11: iload_1
12: iload_2
13: if_icmpge 49
16: aload_3
17: checkcast #3 // class java/lang/Comparable
20: aload_0
21: iload_1
22: invokeinterface #2, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
27: invokeinterface #4, 2 // InterfaceMethod java/lang/Comparable.compareTo:(Ljava/lang/Object;)I
The compiler has inserted an implicit cast to Comparable
so that the compareTo
method can be called. It has asserted that the objects in the list are Comparable
because of the second upper bound, Comparable<? super T>
.
32: ifge 43
35: aload_0
36: iload_1
37: invokeinterface #2, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
42: astore_3
43: iinc 1, 1
46: goto 11
49: aload_3
50: areturn
}