Java泛型:通配符

Jon*_*lor 6 java generics

因此,我正在阅读泛型,以便重新熟悉这些概念,特别是在涉及通配符的情况下,因为我几乎没有使用它们或碰到它们.从我所做的阅读中我无法理解为什么他们使用通配符.我不断遇到的一个例子如下.

void printCollection( Collection<?> c ) {
  for (Object o : c){
    System.out.println(o);
  }
}
Run Code Online (Sandbox Code Playgroud)

为什么你不写这个:

<T> void printCollection( Collection<T> c ) {
    for(T o : c) {
        System.out.println(o);
    }
}
Run Code Online (Sandbox Code Playgroud)

来自oracle网站的另一个例子:

public static double sumOfList(List<? extends Number> list) {
    double s = 0.0;
    for (Number n : list)
        s += n.doubleValue();
    return s;
}
Run Code Online (Sandbox Code Playgroud)

为什么这不是写的

public static <T extends Number> double sumOfList(List<T> list) {
    double s = 0.0;
    for (Number n : list)
        s += n.doubleValue();
    return s;
}
Run Code Online (Sandbox Code Playgroud)

我错过了什么吗?

Rau*_*fio 3

来自甲骨文

出现的一个问题是:什么时候应该使用泛型方法,什么时候应该使用通配符类型?为了理解答案,让我们检查 Collection 库中的一些方法。

interface Collection<E> {
     public boolean containsAll(Collection<?> c);
     public boolean addAll(Collection<? extends E> c);
 }
Run Code Online (Sandbox Code Playgroud)

我们可以在这里使用通用方法:

interface Collection<E> {
     public <T> boolean containsAll(Collection<T> c);
     public <T extends E> boolean addAll(Collection<T> c);
     // Hey, type variables can have bounds too!
 }
Run Code Online (Sandbox Code Playgroud)

然而,在 containsAll 和 addAll 中,类型参数 T 只使用一次。返回类型不依赖于类型参数,也不依赖于该方法的任何其他参数(在本例中,只有一个参数)。这告诉我们类型参数被用于多态性;它的唯一作用是允许在不同的调用站点使用各种实际参数类型。如果是这种情况,应该使用通配符。通配符旨在支持灵活的子类型,这就是我们在这里试图表达的内容。

因此,对于第一个示例,这是因为操作不依赖于类型。

对于第二个,这是因为它仅取决于 Number 类。