9

While I was trying to solve exercise from generics tutorial Q&A My answers were slightly different

My Answers

public static <T extends Comparable<? super T>>
    T max(List<? extends T> list, int begin, int end) //Option1

public static <T extends Comparable<T>>
    T max(List<? extends T> list, int begin, int end) //Option2

from quoted answer below

So My question is

  • Option1 :Would it make any difference if T extends Object & Comparable<? super T> is replaced with T extends Comparable<? super T>. Isn't extends Object implicit ?

  • Option2 :Would it make any difference if Comparable<? super T> is replaced with Comparable<T> ? if so How ?

  • Eclipse code completion creates local variable List<? extends Comparable<? super Comparable<? super T>>> list; on Ctrl+1 max(list, 1, 10); which is bit lengthy. How to Define a classes (hierarchy) that extends Comparable<? super T> , create list and add instances to the list and invoke below method ? Basically I want to know how to invoke max() after adding class instances A or B into a list where class B extends A


Write a generic method to find the maximal element in the range [begin, end) of a list.

Answer:

import java.util.*;

public final class Algorithm {
    public static <T extends Object & Comparable<? super T>>
        T max(List<? extends T> list, int begin, int end) {

        T maxElem = list.get(begin);

        for (++begin; begin < end; ++begin)
            if (maxElem.compareTo(list.get(begin)) < 0)
                maxElem = list.get(begin);
        return maxElem;
    }
}
Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
Prashant Bhate
  • 10,907
  • 7
  • 47
  • 82
  • 2
    Partially answered here: http://stackoverflow.com/questions/10339338/t-extends-object-e-vs-t-extends-e – Andrey Adamovich Aug 23 '13 at 20:51
  • I don't really understand your 3rd question. Can you elaborate onto that a little? – Rohit Jain Aug 23 '13 at 21:02
  • For which method invocation does eclipse create that local variable? I don't see why would it do so. At least nested Comparable generic type is really not reasonable here. – Rohit Jain Aug 23 '13 at 21:21
  • I think I've already added the answer to your 3rd question. You can check the `Parent`, `Child` code there. I guess that is what you want. – Rohit Jain Aug 23 '13 at 21:27
  • @RohitJain It gets inserted by eclipse when you type `max(list, 1, 10);` and do ctrl1 and select 'create local variable list' . Yes you have answered 3rd Thanks:) . I was just bit confused when eclipse created that lengthy declaration – Prashant Bhate Aug 24 '13 at 12:25

2 Answers2

8

Would it make any difference if Comparable<? super T> is replaced with Comparable<T> ? if so How ?

Remember that Comparables are always consumers, i.e., a Comparable<T> consumes T instances, so it should always be preferrable to use Comparable<? super T> instead of Comparable<T> (Quoting - PECS). It would make difference in case you are comparing a type whose super class implements a Comparable<SuperType>. Consider the following code:

class Parent implements Comparable<Parent> {
    protected String name;

    @Override
    public int compareTo(Parent o) {
        return this.name.compareTo(o.name);
    }
}

class Child extends Parent {
    public Child(String name) {
        this.name = name;
    }
}

Now if you give your type parameter as T extends Comparable<T>, you won't be able to call that method for List<Child>, as Child does not implement Comparable<Child> but Comparable<Parent>:

public static <T extends Comparable<T>> T max(List<? extends T> list, int begin, int end) {
    ...
}

public static void main(String[] args) {
    List<Child> list = new ArrayList<Child>();
    max(list, 0, 2);  // Error with current method. Child does not implement Comparable<Child>
}

Hence the type parameter bounds should be T extends Comparable<? super T>.

Note that, you can't change your Child class to:

class Child extends Parent implements Comparable<Child>

because in that case, Child class would extend from different instantiation of same generic type, which is not allowed.


Would it make any difference if T extends Object & Comparable<? super T> is replaced with T extends Comparable<? super T>. Isn't extends Object implicit ?

Well, there is a difference between the two bounds. In the 1st bound, the erasure of the type parameter is Object, whereas in the 2nd bound, the erasure is Comparable.

So, without Object bound, your code will compile to:

public static Comparable max(List list, int begin, int end)

The issue might come when you are generifying the legacy non-generic code. It's neccessary to give Object also as upper bound to avoid breaking the Byte Code compatibility. You can read more about it on this link: Angelika Langer - Programming Idioms

Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
  • The erasure of a method only makes a difference for the input parameter types, not the return type, and the `Object` bound doesn't make a difference there: it's still `max(List, int, int)`. The `Object` is genuinely unnecessary here. – Louis Wasserman Aug 23 '13 at 21:10
  • @LouisWasserman. Well, on first look I also thought the same, then I read on the link which I have added at the end. It's saying that it's necessary for maintaining byte code compatibility. – Rohit Jain Aug 23 '13 at 21:11
  • @RohitJain In fact `max(list, 0, 2);` will compile fine. but `Child child = max(list, 0, 2);` won't compile. – Kachna Dec 17 '15 at 18:33
0

It looks like there are more wildcards than necessary. I'll probably go with

public static <T extends Comparable<? super T>>
    T max(List<T> list, int begin, int end)

An even more constrained version:

public static <T extends C, C extends Comparable<C>>
    T max(List<T> list, int begin, int end)

i.e. T must have a super type that is comparable to itself. For example T cannot be Foo

    class Foo implements Comparable<Object>

Foo does not make sense anyway; a Comparable can only be meaningfully compared to its own kind. The clause C extends Comparable<C> acknowledges that fact.

ZhongYu
  • 19,446
  • 5
  • 33
  • 61