实例化泛型:new ArrayList<?>() vs new ArrayList<List<?>>()

4

为什么这是被允许的:

List<List<?>> list = new ArrayList<List<?>>()

但不包括这个?

List<?> list = new ArrayList<?>(); //Compile error: "Cannot instantiate the type ArrayList<?>"
3个回答

3
当你创建一个ArrayList时,你需要定义它所包含的对象类型:
  • 在第一个示例中,你创建了一个ArrayList,它将包含未知泛型类型的List,但它们都是List。
  • 在第二个示例中,你试图创建一个未知类型的ArrayList,这是不允许的。

1

如果使用未知泛型,就不能实例化对象,这就是为什么第二行会失败。

List<?> list = new ArrayList<String>();

使用"list"时,代码不知道它是一个字符串列表,因此无法正常工作。第一次调用可以工作,因为您指定要创建其他列表的数组列表,当您实例化子列表时,这些列表将确定。在这里,您只实例化了父列表,它实际上是一个列表的列表。

0

将通用类型定义视为以下两个方面:

  1. 某种构造函数的定义,以便能够创建通用类型的新非通用“类型实例”。
  2. 类型定义。

现在让我们将这种逻辑转化为非通用变量:

CharSequence val = new String("foo");

这是完全合法的。变量val代表一种类型(2),当然永远不会直接实例化接口CharSequence。但是,您可以将可分配的子类型分配给它,例如String。您不能通过类似于new [? extends CharSequence]的语句替换字符串的创建,必须明确命名要构造的类型。

现在让我们回到泛型,那里的事情也很相似。当您调用泛型类型的构造函数时。

new ArrayList<List<?>>()

你正在某种程度上构建一个泛型类型的新“类型实例”,在其中需要显式地为泛型定义中的类型变量 T 分配一个值,如 ArrayList<T>? 本身并没有描述 Java 类型,因此不能用作赋值值。但是,除了 T = ? 之外,定义 T = List<?> 是可能的,因为通配符可以是有效的 Java 类型定义的一部分。

类型定义(1)中使用通配符时,例如

List<?> list

您并未构造一个新的泛型类型,而是仅仅描述了其中的边界。因此,在这种情况下可以使用通配符。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接