为什么Java不允许注入嵌套泛型?

4
如果我写下以下代码:
List<List<String>> strings = new ArrayList<ArrayList<String>>();

我收到以下编译器错误信息:
Type mismatch: cannot convert from ArrayList<ArrayList<String>> to List<List<String>>

为什么?

只是猜测:因为内部嵌套的ArrayList没有new语句。 - Robert Harvey
不行,因为我可以写List<ArrayList<String>> strings = new ArrayList<ArrayList<String>>(); 这是合法的! - user1768830
4个回答

8

泛型不是协变的,所以你需要使用:

List<List<String>> strings = new ArrayList<List<String>>();

注意外部右侧的声明 ArrayList 可以“变成”List。但是,对于出现在泛型内部的任何内容都不适用。

谢谢Reimeus - 我不熟悉协变性,您能详细说明一下它在泛型中的含义吗? - user1768830
@TicketMonster:如果您可以传递 ArrayList<String> 到期望 List<String> 的位置,那么它将是协变的。我认为这就是为什么添加了 ? extends? super 的原因之一。 - Bhesh Gurung
@TicketMonster:或者List<? extends List<String>> strings = new ArrayList<ArrayList<String>>();,这可能不是你想要的。 - Bhesh Gurung
1
@TicketMonster 查看更新。这是编译器为了防止不相似的派生对象被存储在集合中所采取的保护方式。 - Reimeus

1

你可以编写你想要的代码,只需要更新你的初始化:

List<List<String>> strings = new ArrayList<List<String>>();

然后,对于每个想要添加到外部列表中的项目:

strings.add(new ArrayList<String>());

是的,但为什么(这就是我的问题!)? - user1768830

0

如果允许这样做,你可能会在某个时候依赖于列表是ArrayList列表,而在其他地方插入其他内容。

例如,这样做也是合法的:

ArrayList<ArrayList<String>> arrayLists = new ArrayList<ArrayList<String>>();
List<List<String>> unknownLists = arrayLists ;
unknownLists.append(new LinkedList<String>());
for (ArrayList<String> l : arrayLists ) // (1)
  System.out.println(l);

这段代码可以编译通过,但在(1)处会抛出ClassCastException异常。


0

你不能这样做,因为类型是不变的。但是,你可以这样写:

List<? extends List<String>> strings = new ArrayList<ArrayList<String>>();

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