4

I have a three class: 1.class Algorithm having max() finding maximum value in a Collection:

public class Algorithm {

    public static <T extends Comparable<T>> T max(Collection<? extends T> coll) {
        T max = coll.iterator().next();

        for (T elm : coll) {
            if (max.compareTo(elm) < 0)
                max = elm;
        }

        return max;
    }
}

2.Class Fruit:

public class Fruit implements Comparable<Fruit> {
    private String name;
    private int size;

    public Fruit(String name, int size) {
        this.name = name;
        this.size = size;
    }

    public int compareTo(Fruit that) {
        if (size < that.size)
            return -1;
        else if (size == that.size)
            return 0;
        else
            return 1;
    }
}

3.class Apple extending Fruit:

public class Apple extends Fruit {
    public Apple(int size) {
        super("Apple", size);
    }
}

Now the question is this:

public class Main
{
    public static void main(String[] args) {        
        Apple a1 = new Apple(10);
        Apple a2 = new Apple(34);

        List<Apple> apples = Arrays.<Apple>asList(a1, a2);

        System.out.println(Collections.max(apples).size);
    }
}

According to this post Java - Syntax Question: What is I should wrote it this way: public static <T extends Comparable<? super T>> T max(Collection<? extends T> coll). But it is working fine now.Why? Class Apple does not implement Comparable<Apple> and there is no super.

[UPDATE]
Java Generics and Collections Book says:

Without the super wildcard, finding the maximum of a List<Apple> would be illegal, even though finding the maximum of a List<Fruit> is permitted.

Community
  • 1
  • 1
Majid Azimi
  • 5,575
  • 13
  • 64
  • 113
  • FYI: Guava's [`Ints`](http://guava-libraries.googlecode.com/svn/tags/release09/javadoc/com/google/common/primitives/Ints.html) class has a [`compare(int, int)`](http://guava-libraries.googlecode.com/svn/tags/release09/javadoc/com/google/common/primitives/Ints.html#compare%28int,%20int%29) method to make `int` comparisons easier. – Adam Paynter Jul 15 '11 at 08:47
  • @AdamPaynter Java 7's `Integer` class now provides that same method. – Matt Ball Mar 04 '13 at 21:07

4 Answers4

6

Suppose we changed the max method to this:

<T extends Comparable<T>> T max(Collection<? extends T> coll)

You would not be able to get the max of a List<Apple> because Apple does not implement Comparable<Apple>, it implements Comparable<Fruit>. But you and I know perfectly well that an Apple knows how to compare itself to another Fruit because it inherited that functionality.

We fix the problem by changing the declaration of max to this:

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

This means that we accept any class T such that:

  1. T implements Comparable<T>, or...
  2. T implements Comparable<X> for some X such that X is a super class of T

In order to find the max, we must be sure that any instance of T can safely accept another instance of T as an argument to its compare method.

In the first scenario, it is obvious that any instance of T can safely accept another instance of T as an argument to its compare(T) method.

In the second scenario, any instance of T can safely accept another instance of T as an argument to its compare(X) method because all instances of T are also instances of X.

Your example illustrates the second scenario, where T corresponds to Apple and X corresponds to Fruit.

Adam Paynter
  • 46,244
  • 33
  • 149
  • 164
1

You use Collections.max(apples) instead of Algorithm.max.

Collections.max has slightly different declaration:

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
Sergey Aslanov
  • 2,397
  • 15
  • 16
  • My question is: without `Comparable super T>` it should not work because with this `Comparable` class `Apple` should implement `Comparable` which isn't implemented here. – Majid Azimi Jul 15 '11 at 08:25
  • When I change `Collections.max` to `Algorithm.max` in your sample it doesn't work as it's supposed to. – Sergey Aslanov Jul 15 '11 at 08:36
0

sorry for bringing this back but I think it's important. Has your code stopped working properly when changed from Collections.max() to Algorithm.max()? I've done a simmilar test in jdk8 and I don't understand why it's working fine while according to Java Generics and Collections it should not.

I have a Fruit abstract class (implementing Comparable):

public abstract class Fruit implements Comparable<Fruit> {
    private String name;
    private int size;

    public Fruit(String name, int size) {
        this.name = name;
        this.size = size;
    }

    public int compareTo(Fruit that) {
        if (size < that.size)
            return -1;
        else if (size == that.size)
            return 0;
        else
            return 1;
    }
}

Then I have a Apple extending Fruit class:

public class Apple extends Fruit {
    public Apple(String name, int size) {
        super(name, size);
    }
}

And finally:

 public class GenericsTest {

    @Test
    public void test1() {
        final Apple a1 = new Apple("apple1", 50);
        final Apple a2 = new Apple("apple2", 70);
        final Apple a3 = new Apple("apple3", 34);

        final List<Apple> apples = Lists.newArrayList(a1, a2, a3);

        System.out.println(GenericsTest.max(apples).getSize());
    }

    private static <T extends Comparable<T>> T max(Collection<? extends T> coll) {
        T max = coll.iterator().next();

        for (T elm : coll) {
            if (max.compareTo(elm) < 0)
                max = elm;
        }

        return max;
    }
}

The code is working while there is no ? super T in the max method's signature and the List is of Apple type. According to the quote you mentioned it shouldn't be working. I seem to be puzzled here...

onlyahobo
  • 3
  • 2
0

let's try to see what happens when you remove <? super T>

public class CollectionMinSignature {
    
    public static <T extends Object & Comparable</*? super*/ T>> T min(Collection<? extends T> coll) {
    
        Iterator<? extends T> i = coll.iterator();
        T candidate = i.next();

        while (i.hasNext()) {
            T next = i.next();
            if (next.compareTo(candidate) < 0)
                candidate = next;
        }
        return candidate;
    }
    
    public static class A implements Comparable<A> {
        private int i;
        public A (int i) {
            this.i = i;
        }
        @Override
        public int compareTo(A a) {
            return this.getVal() - a.getVal();
        }
        public String toString() {
            return Integer.toString(i);
        }
        public int getVal() {
            return this.i;
        }
    }
    public static class B extends A {
        public B(int i) {
            super(i);
        }
    }
    
    public static void main(String[] args) {
    
    Collection<B> coll = new ArrayList<B>(List.of(new B(0), new B(1), new B(-1)));
    
    B b = min(coll); /*it doesn't work*/
    B b2 = Collections.min(coll); /*it works*/
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 01 '23 at 12:21