Java 泛型,未绑定通配符 <?> 与 <Object>

Java generics, Unbound wildcards <?> vs <Object>

我已经阅读了一些主题,其中涵盖了有关泛型的某些问题,例如它们的 relationship with raw types. But I'd like an additional explanation on a certain line found in the Java SE tutorial on unbound generics

根据一句话:

The goal of printList is to print a list of any type, but it fails to achieve that goal — it prints only a list of Object instances; it cannot print List<Integer>, List<String>, List<Double>, and so on, because they are not subtypes of List<Object>.

如果我理解这句话; List<?>List<Object> 之间的区别在于,我们可以通过实现前者来使用类型参数 List<String>List<Integer>。而如果我们实现后者,我们只能使用类型参数 List<Object>。好像 List<?>Object 的上限,即 List<? extends Object>.

但是接下来的句子让我感到困惑,因为根据我之前的理解,List<Object> 应该只包含 class Object 的实例,而不是其他东西。

It's important to note that List<Object> and List<?> are not the same. You can insert an Object, or any subtype of Object, into a List<Object>. But you can only insert null into a List<?>.

这里有两个不同的问题。 List<Object> 实际上可以像你说的那样接受任何对象。 List<Number> 可以接受 至少 Number 个对象,当然也可以是任何子类,例如 Integer.

但是这样的方法:

public void print(List<Number> list);

实际上只会取一个List正好List<Number>。它不会采用任何声明为 List<Integer>.

的列表

所以不同之处在于 List<?> 将采用任何带有任何声明的列表,但 List<Object> 采用 声明的内容List<Object> 相同,仅此而已。

最后一句话简单地指出,List<?> 是一个列表,您根本不知道其项目是什么类型。因此,除了 null.

之外,您不能向其中添加任何内容

让您感到困惑的句子试图警告您,虽然 List<?> 是所有通用列表的超类型,但您不能向 List<?> 集合添加任何内容。

假设您尝试了以下代码:

private static void addObjectToList1(final List<?> aList, final Object o ) {
    aList.add(o);
}

private static void addObjectToList2(final List<Object> aList, final Object o ) {
    aList.add(o);
}

private static <T> void addObjectToList3(final List<T> aList, final T o ) {
    aList.add(o);
}


public static void main(String[] args) {
    List<String> testList = new ArrayList<String>();
    String s = "Add me!";
    addObjectToList1(testList, s);
    addObjectToList2(testList, s);
    addObjectToList3(testList, s);
}

addObjectToList1 无法编译,因为除了 null 之外你不能添加任何东西到 List<?>。 (这就是这句话想告诉你的。)

addObjectToList2 编译,但在 main() 中调用它不编译,因为 List<Object> 不是 List<String>.[=21= 的超类型]

addObjectToList3 编译和调用都有效。这是将元素添加到通用列表的方法。