I'm having a hard time trying to figure out why the two methods declarations have different results.
On the first method signature its obvious you can't compare Apples with Apples and Oranges with Orange, because none of them implement Comparable<>.
But on the second method I was surprised that you could actually compare Apples with Apples and Oranges with Oranges.
I remember on a previous version of IntelliJ (14) a call to the second method with a List of Apples or Oranges was giving a compilation error. But the newer versions of IntelliJ don't report that problem anymore.
I would appreciate if someone could explain me what's the difference between the two methods signatures using the Fruit example.
class Fruit implements Comparable<Fruit> {}
class Apple extends Fruit {
}
class Orange extends Fruit {
}
static <T extends Comparable<T>> T maxSimple(Collection<T> coll) {
}
static <T extends Comparable<T>> T max(Collection<? extends T> coll) {
}
Best Answer
What are the constraints on T?
In your first example, T must equal the collection type and be comparable to exactly itself. Note that
List<Apple>
does not extendList<Fruit>
, and if it did, you could addOranges
to the apple list.Try
T
asApple
:Apple
is notComparable<Apple>
, so this fails. TryT
asFruit
:Collection<Fruit>
is not a supertype ofCollection<Apple>
, so this failsIn your second example, you allow the collection type to range over the subtypes of
T
, so T can beFruit
and you haveCollection< any fruit subtype >
There is a third option that you havent considered:
Here we allow T to be bound to Apple, as Apple is comparable to one of its superclasses