5

我需要使用带有列表的地图:

Map<String, List<String>> keyToGroup = new HashMap<String, ArrayList<String>>();

我在 eclipse 的这一行上遇到编译器错误。

唯一可行的事情似乎是将 Map 中的内部 List 更改为 ArrayList

Map<String, ArrayList<String>> keyToGroup = new HashMap<String, ArrayList<String>>();

我不得不更改许多接口方法的签名,但我仍然不明白;为什么第一个定义不起作用?

是不是一样,不应该

Map<String, List<String>> keyToGroup 

&

Map<String, ArrayList<String>>

是相同的?

4

3 回答 3

8

不,他们不是。考虑一下:

Map<String, List<String>> keyToGroup = new HashMap<String, ArrayList<String>>();
keyToGroup.put("foo", new LinkedList<String>());

第二行很好,因为 aLinkedList<String>是 a List<String>- 但就将其添加到 a 而言,它在逻辑上并不好HashMap<String, ArrayList<String>>因为 aLinkedList<String>不是a 。ArrayList<String>

为了更清楚:

Map<String, ArrayList<String>> map1 = new HashMap<String, ArrayList<String>>();
Map<String, List<String>> map2 = map1; // This is invalid
map2.put("foo", new LinkedList<String>());
ArrayList<String> oops = map1.get("foo"); // Because this would be broken

这不仅仅是将集合作为类型参数的情况。使用普通继承更简单:

List<Banana> bunchOfBananas = new ArrayList<Banana>();
List<Fruit> fruitBowl = bunchOfBananas; // Invalid!
fruitBowl.add(new Apple());
Banana banana = bunchOfBananas.get(0);

即使每个香蕉都是水果,所以“香蕉集合”是“水果集合*”,在获取它们的意义上,并不是每个水果都是香蕉。

在某些情况下,您可以使用通配符参数化类型来提供帮助,但这完全取决于您要实现的目标。

于 2013-09-19T06:33:09.440 回答
0

如果您需要在 Map 或任何 List 中实现特定的列表,请问自己一个问题?在特定实现的情况下,您可以使用最后一个示例:

Map<String, ArrayList<String>> keyToGroup = new HashMap<String, ArrayList<String>>();

如果有任何列表,请使用:

Map<String, List<String>> keyToGroup = new HashMap<String, List<String>>();
keyToGroup.put("arraylist", new ArrayList<String());
keyToGroup.put("linkedlist", new LinkedList<String());

顺便说一句,从设计的角度来看,第二个选项通常更好,所以如果您现在不确切知道 - 请先尝试使用第二个选项。

于 2013-09-19T06:41:17.473 回答
0

不,他们不是。泛型在 Java 中不是协变的。

如果它们是协变的,您可以在逻辑上放置任何类型的,List而不是ArrayList违背拥有泛型的目的。

考虑阅读 Effective Java (2nd Edition) Chapter 5: Generics,它对泛型有很好的解释。

另一个很好的读物是http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html

于 2013-09-19T06:37:46.123 回答