Java泛型和向上转型

5

请问有人可以解释一下为什么会出现这种情况吗?

Map<String, List<String>> foo = new HashMap<String, LinkedList<String>>();

产生了类型不匹配的错误?

类型不匹配:无法将HashMap<String,LinkedList<String>>转换为Iterators.Map<String,List<String>>

HashMap实现了Map接口,而LinkedList实现了List接口。此外,这个

List<String> foo = new LinkedList<String>();

works...

Thanks


类似的问题:https://dev59.com/J0_Sa4cB1Zd3GeqP8QCO - Mark Peters
4个回答

6
因为Map<String, List<String>>允许你将ArrayList<String>放入其中,但这样做会违反HashMap<String, LinkedList<String>>的类型完整性。
要么将你的HashMap声明为HashMap<String, List<String>>,要么将你的变量声明为Map<String, LinkedList<String>>Map<String, ? extends List<String>>

编辑

更紧急的问题是你导入了错误的Map类(某个叫做Iterators.Map的类),或者在这段代码所在的包中有另一个名为Map的类(或内部类)。你需要导入java.util.Map

我没有考虑到那个。但在这种情况下,AlexR的解决方案应该可以工作,对吗?我已经达到了Java类型检查的限制吗? - Simon
@Simon:我不确定他的解决方案与我的建议有何不同,但是如果您不想知道列表将是LinkedLists(并且在修复我在Alex的答案中评论的导入错误之后),HashMap<String,List<String>>将起作用。 - Mark Peters

4

在Java中,泛型不保留子类型协变性。因此,如果B是A的子类型,则Gen(B)可能不是Gen(A)的子类型,其中Gen是某种类型的通用用法。

具体而言,如果LinkedList是List的子类型,则这并不意味着Map<String,LinkedList>是Map<String,List>的子类型。正如其他帖子所建议的那样,在HashMap类型参数中,您必须使用List作为您的类型。


是的,但是(保持B作为A的子类型),B<T>应该是A<T>的子类型。很明显,在Java JDK 1.6中这并不正确。 - Simon
@Simon:实际上这是真的。但这并不意味着B<V extends T>可以分配给A<T> - Mark Peters

1

请按照以下方式进行修复:

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

请注意,我在赋值语句的右侧将LinkedList更改为List

您是正确的,LinkedList实现了List。但我认为这个错误的解释不在于List的定义,而在于接口Map<K,V>的定义。

表达式的左侧表示您想要创建String和List的Map,即V被List“替换”。右侧使用LinkedList。尽管LinkedList实现了List,但它不起作用,因为Map的定义不是像Map<K, V extends List>这样的东西,所以编译器需要精确匹配。

我不确定我的描述是否严格,但无论如何,这是正确泛型的方法。实际上,当您创建列表映射时,您并不关心列表的实现方式,因此说HashMap<String, List<String>>。只有在创建列表实例时才关心其实现方式。这将允许您在不修改其他代码的情况下更改实现。


你在最后一条评论中说得对,我在实例化map时不应该关心确切的类型。但是我几分钟前尝试了你的解决方案,又一次遇到了类型不匹配的错误: “类型不匹配:无法从HashMap<String,List<String>>转换为Iterators.Map<String,List<String>>” - Simon
@Simon: 看起来你导入了错误的Map类;我不确定Iterators.Map是什么,但你需要java.util.Map。很抱歉我们都没有在你原始信息中发现这个问题。 - Mark Peters
糟糕...因为Eclipse自动补全功能,我失去了45分钟的工作时间...非常感谢你的帮助!! - Simon
@Mark,我认为你是对的,但他更可能导入了错误的List:java.awt.List而不是java.util.List。这至少是我每天都会做的事情... - AlexR
@Alex:我知道我是对的(看看引用“Iterators.Map”的错误消息),并且他没有错误地导入“List”,因为这一部分在他那里工作正常(请参见问题的最后一个代码段)。但是,我也经常犯“java.awt.List”的错误。 - Mark Peters

0
请使用HashMap的接口:
Map<String, List<String>> foo = new HashMap<String, List<String>>();

List<String> bar = new LinkedList<String>();

foo.put("barkey", bar);

谢谢,就像我告诉AlexR的那样,我尝试了那个方法,但它仍然给我同样的类型不匹配错误。 - Simon

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