Collections.max签名的说明

时间:2014-12-15 12:40:42

标签: java generics

当我偶然发现这个方法签名时,我正在阅读一篇关于Java Generics的文章:

static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll);

我没有得到的部分是为什么我们需要

Collection<? extends T> coll

不会

Collection<T> coll

还做什么?

有人可以解释为什么下面的签名不够吗?

static <T extends Object & Comparable<? super T>> T max(Collection<T> coll);

提前感谢您的回复。这让我困惑了很长一段时间..

1 个答案:

答案 0 :(得分:12)

Gábor是对的。通配符允许返回对象的静态类型与您输入的集合的声明参数类型不同。例如,给定这些类:

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

这节课:

class Test {

    @Nullable
    static <T extends Comparable<? super T>> T extendsMax(
            Collection<? extends T> coll) {
        return null;
    }

    @Nullable
    static <T extends Comparable<? super T>> T max(Collection<T> coll) {
        return null;
    }
}

观察编译调用和调用不调用的内容:

public static void main(String[] args) {
    final Collection<S> sColl = new ArrayList<>();
    final Collection<A> aColl = new ArrayList<>();
    final Collection<B> bColl = new ArrayList<>();

    final S s1 = Test.<S> extendsMax(sColl); // compiles, T = S, <? extends T> = S
    final S s2 = Test.<S> extendsMax(aColl); // compiles, T = S, <? extends T> = A
    final S s3 = Test.<S> extendsMax(bColl); // compiles, T = S, <? extends T> = B
    final A a1 = Test.<A> extendsMax(aColl); // compiles, T = A
    final B b1 = Test.<B> extendsMax(bColl); // compiles, T = B

    final S s4 = Test.<S> max(sColl); // compiles, T = S
    final S s5 = Test.<S> max(aColl); // does not compile, T = S, T != A
    final S s6 = Test.<S> max(bColl); // does not compile, T = S, T != B

    final S s7 = Test.max(aColl); // compiles, but because T = A, and A 
                                  // can be assigned to S
}

因此通配符允许一些灵活性。虽然你可以省略通配符(说实话,我想不出一个需要通配符的地方),这是有原因的。


汤姆也不正确。您可以使用通配符将null添加到集合中(如果集合首先支持add()):

List<? extends Number> list = new ArrayList<>();
list.add(null); // compiles, and should execute just fine

因为add()remove()Collection接口中的大多数其他mutator都是可选操作,所以如果参数通过这些方法改变集合是不安全的刚刚声明为Collection。此外,通常可以使用iterator().remove()或类似的东西从集合中删除元素,无论它们是否使用通配符声明,特别是对于已经包含在Java集合框架中的元素。

因此,虽然通配符确实限制了您可以对集合执行的操作,但应该用作防止更改集合的方法。