在Java中,常规泛型不能做外卡吗?

dev*_*747 19 java generics bounded-wildcard unbounded-wildcard

我是Java新手.在 文档中,他们将此作为使用通配符的用例:

static void printCollection(Collection c) {
    Iterator i = c.iterator();
    for (int k = 0; k < c.size(); k++) {
        System.out.println(i.next());
    }
}
Run Code Online (Sandbox Code Playgroud)

这是他们的解决方案:

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

但是我可以在没有外卡的情况下做同样的事情:

static <T> void printCollection(Collection<T> c) {
    Iterator i = c.iterator();
    for (int k = 0; k < c.size(); k++) {
        System.out.println(i.next());
    }
}
Run Code Online (Sandbox Code Playgroud)

有人可以告诉我一个简单的用例,常规的泛型不起作用,但外卡会吗?

更新:此处的答案何时在Java Generics中使用通配符?不要告诉我们需要通配符.事实上,它是另一种方式.

Rad*_*def 4

通配符允许我们做的一件事是声明与特定类型参数无关的类型,例如“任何类型列表的列表”

List<List<?>> listOfAnyList = ...;

listOfAnyList.add( new ArrayList<String>() );
listOfAnyList.add( new ArrayList<Double>() );
Run Code Online (Sandbox Code Playgroud)

如果没有通配符:* 这是不可能的,因为元素列表可能具有彼此不同的类型。

如果我们尝试捕获它,我们会发现我们不能:

static <E> void m(List<List<E>> listOfParticularList) {}

m( listOfAnyList ); // <- this won't compile
Run Code Online (Sandbox Code Playgroud)

通配符允许我们做的另一件事是类型参数不能做的事情是设置下限。(类型参数可以用绑定来声明extends,但不能用super绑定来声明。**)

class Protector {
    private String secretMessage = "abc";

    void pass(Consumer<? super String> consumer) {
        consumer.accept( secretMessage );
    }
}
Run Code Online (Sandbox Code Playgroud)

假设pass改为声明采用Consumer<String>. 现在假设我们有一个Consumer<Object>

class CollectorOfAnything implements Consumer<Object> {
    private List<Object> myCollection = new ArrayList<>();

    @Override
    public void accept(Object anything) {
        myCollection.add( anything );
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是:我们无法将其传递给接受 的方法Consumer<String>。声明Consumer<? super String>意味着我们可以传递任何接受String. (另请参阅Java 泛型:什么是 PECS?

大多数时候,通配符只是让我们做出整洁的声明。

如果我们不需要使用类型,则不必为其声明类型参数。


* 技术上也可以使用原始类型,但不鼓励使用原始类型。

** 我不知道为什么 Java 不允许super使用类型参数。4.5.1. 参数化类型的类型参数可能暗示它与类型推断的限制有关:

与方法签名中声明的普通类型变量不同,使用通配符时不需要类型推断。因此,允许声明通配符的下限 [...]。