“收藏<>”和“收藏<T”有什么区别>

我主要是一名C#开发人员,我正在向我的朋友教授数据结构,他们在大学里使用Java,我在Java中看到了这样的表达:

void printCollection(Collection<?> c) {
    for (Object e : c) {
        System.out.println(e);
    }
}

我没有在C#中看到这样的东西,所以我想知道Java和Java有什么区别?Collection<T>Collection<?>

void printCollection(Collection<T> c) {
    for (Object e : c) {
        System.out.println(e);
    }
}

我认为它也可以用上面的方式写。文档中的家伙正在比较,不过。Collection<Object>Collection<T>

示例取自 http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html


答案 1

Collection<?>是未知类型参数的集合。

就调用方而言,两者之间没有区别

void printCollection(Collection<?> c) { ... }

<T> void printCollection(Collection<T> c) { ... }

但是,后者允许实现引用集合的类型参数,因此通常是首选。

前一种语法之所以存在,是因为并不总是能够在适当的范围内引入类型参数。例如,考虑:

List<Set<?>> sets = new ArrayList<>();
sets.add(new HashSet<String>());
sets.add(new HashSet<Integer>());

如果我用某个类型参数替换,则 中的所有集合都将被限制为相同的组件类型,即我不能再将具有不同元素类型的集合放入同一列表中,如以下尝试所示:?Tsets

class C<T extends String> {
    List<Set<T>> sets = new ArrayList<>();

    public C() {
        sets.add(new HashSet<String>()); // does not compile
        sets.add(new HashSet<Integer>()); // does not compile
    }
}

答案 2

声明(发音为“未知的集合”)是其元素类型与任何内容匹配的集合,而代表类型的集合。Collection<?>Collection<T>T

像往常一样,Angelika Langer关于泛型的FAQ对这个主题进行了广泛的讨论,这是一本关于Java中泛型的必读书,特别是无界通配符(这个问题的主题)。引用常见问题解答:

无界通配符看起来像 “ ? ” 并代表所有类型的族。无界通配符用作泛型类型实例化的参数。无界通配符在不需要了解参数化类型的类型参数的情况下很有用

有关更多技术细节,请查看 Java 语言规范§4.5.1 类型参数和通配符部分,其中指出:

类型参数可以是引用类型或通配符。在只需要部分了解类型参数的情况下,通配符很有用。