<T extends Comparable<? super T>> 的问题

4

我有三个类:1. Algorithm 类,其中 max() 方法可以在 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.类 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. 类 Apple 继承自 Fruit

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

现在的问题是:
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);
    }
}

根据这篇文章,我应该这样写:public static <T extends Comparable<? super T>> T max(Collection<? extends T> coll)。但是现在它正常工作了。为什么?类Apple没有实现Comparable<Apple>,也没有使用super
[更新]
Java泛型和集合书中说:

如果没有使用super通配符,查找List<Apple>的最大值将是非法的,即使查找List<Fruit>的最大值是允许的。


FYI:Guava的Ints类有一个compare(int, int)方法,使得int比较更加容易。 - Adam Paynter
@AdamPaynter Java 7的Integer类现在提供了相同的方法。 - Matt Ball
4个回答

6
假设我们将max方法更改为以下内容:
<T extends Comparable<T>> T max(Collection<? extends T> coll)

您不能获取 List<Apple>max 值,因为 Apple 没有实现 Comparable<Apple>,而是实现了 Comparable<Fruit>。但是我们都知道,Apple 继承了这个功能,它知道如何将自己与另一个 Fruit 进行比较。
我们通过将 max 的声明更改为以下内容来解决问题:
<T extends Comparable<? super T>> T max(Collection<? extends T> coll)

这意味着我们接受任何一个类 T,满足以下条件之一:
  1. T 实现了 Comparable<T>或者...
  2. T 实现了 Comparable<X>,其中 XT 的超类。
为了找到 max,我们必须确保 T 的任何实例都可以安全地将另一个 T 实例作为其 compare 方法的参数。
在第一种情况下,显然任何 T 的实例都可以安全地将另一个 T 实例作为其 compare(T) 方法的参数。
在第二种情况下,任何 T 的实例都可以安全地将另一个 T 实例作为其 compare(X) 方法的参数,因为所有 T 的实例也都是 X 的实例。
你的示例说明了第二种情况,其中 T 对应于 AppleX 对应于 Fruit

1
你使用 Collections.max(apples) 而不是 Algorithm.maxCollections.max 的声明略有不同:
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)

我的问题是:如果没有 Comparable<? super T>,它应该无法工作,因为使用这个 Comparable<T> 类,Apple 应该实现 Comparable<Apple>,但这里没有实现。 - Majid Azimi
当我在你的示例中将 Collections.max 更改为 Algorithm.max 时,它不能按预期工作。 - Sergey Aslanov

0

抱歉再次提出这个问题,但我认为这很重要。当您将代码从Collections.max()更改为Algorithm.max()时,代码是否停止正常工作?我在jdk8中进行了类似的测试,但我不明白为什么它可以正常工作,而根据Java Generics和Collections的说法,它不应该。

我有一个水果抽象类(实现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;
    }
}

然后我有一个扩展了水果类的苹果:

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

最后:

 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;
    }
}

当max方法的签名中没有? super T,而List是Apple类型时,代码可以正常工作。根据您提到的引用,它不应该起作用。我在这里感到困惑...


0

让我们尝试一下,看看当你移除 <? 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*/

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接