Reputation: 5745
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 aList<Apple>
would be illegal, even though finding the maximum of aList<Fruit>
is permitted.
Upvotes: 4
Views: 5732
Reputation: 1
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*/
Upvotes: 0
Reputation: 3
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...
Upvotes: 0
Reputation: 46918
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:
T implements Comparable<T>
, or...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
.
Upvotes: 6
Reputation: 2415
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)
Upvotes: 1