3

Is there a practical difference between these two signatures:

public static <T extends Comparable<? super T>> T max(Collection<T> c) 

and

public static <T extends Comparable<T>> T max(Collection<? extends T> c) 

I cannot think of a single use case where these two would not be interchangeable.

Then what is the reason for having both ? super T and ? extends T in the standard max() method in the Java Collections:

public static <T extends Comparable<? super T>> T max(Collection<? extends T> coll)

Edit: This question is not about the difference between <? super T> and <? extends T>. The get/put principle is quite clear to me. The question is about the difference between these 2 particular signatures and why did the creators of the Java Collections API decided to create a mix out of these two signatures for their standard "max" function.

mdzh
  • 897
  • 1
  • 13
  • 30
  • possible duplicate of http://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java – Japu_D_Cret Mar 24 '17 at 13:36
  • Possible duplicate of [Difference between super T> and extends T> in Java](http://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java) – Tom Mar 24 '17 at 13:37
  • A more interesting question is is there any difference between the `Collection extends T> coll` in the parameters of the standard max() method and if it were declared `Collection coll` – newacct Apr 01 '17 at 00:41

3 Answers3

2

An example when the two are not interchangeable is:

static class A implements Comparable<Object> {
    @Override
    public int compareTo(final Object o) {
        return 0;
    }
}

a list with instances of A works with the first max() and fails for the second max():

error: method max2 in class Generics cannot be applied to given types;
    max2(Arrays.asList(new A()));
    ^
required: Collection<? extends T>
found: List<A>
reason: inference variable T has incompatible bounds
  equality constraints: Object
  upper bounds: Comparable<T>
where T is a type-variable:
  T extends Comparable<T> declared in method <T>max2(Collection<? extends T>)

another example:

static class A {}
static class B extends A implements Comparable<A>{
    @Override
    public int compareTo(final A o) {
        return 0;
    }
}

max() has been designed this way to make sure its signature is not changed and all the compiled code depending on max() (pre-Java 5 code) returning an Object can still work, more details in Converting Legacy Code to Use Generics.

Adam Siemion
  • 14,533
  • 4
  • 47
  • 84
  • 1
    Yep, correct. Seems these two signatures are not as interchangeable as I thought. Thanks! – mdzh Mar 24 '17 at 14:12
1

Taking a simple example

Animal:

class Animal extends Mammal

Cat:

class Cat extends Animal

Lets break down the signature.

max(Collection<? extends T> coll)

This is because the max should be accepting a list of Animal as well as Cat. Now, the remaining part:

<T extends Comparable<? super T>>

This covers the case where I have my Animal class signature something like this:

Animal extends Mammal implements Comparable<Mammal>

So, my comparable object can accept any of it's parents and still do a logical comparison. I know this isn't a very practical example, but I hope it makes sense.

Vinay Rao
  • 1,284
  • 9
  • 13
0

Then what is the reason for having both ? super T and ? extends T in the standard max() method in the Java Collections:

Is just to offer a max operation that is as versatile as possible given that the operations that it is going to perform on that collection and their elements are just iterator().next and compareTo. In other words it declares the weakest constrains needed on its argument type that still allows its code to compile.

Valentin Ruano
  • 2,574
  • 15
  • 28
  • 1
    The public static > T max(Collection extends T> c) variant of the signature offers exactly that. So in a way I can see why this second variant can be considered slightly better than the first. But I still don't see a valid reason for the mix. – mdzh Mar 24 '17 at 14:04
  • Currently im on my mobile device so is difficult to look at it with detail right now ... but a brainless test is to pull the code of those methods and play with the signatures and see why those changes would result in compilation problems. – Valentin Ruano Mar 24 '17 at 14:10