在我看来它应该有效,但事实并非如此。为什么?源代码:
package javaapplication1;
import java.util.*;
class A
{
public static <K,V> Map<K,V> map()
{
return new HashMap<K,V>();
}
}
class Person {}
class Dog {}
public class JavaApplication1
{
static void f(Map<Person, List<? extends Dog>> peopleDogList) {}
public static void main(String[] args)
{
f(A.<Person, List<Dog>>map());
}
}
非常简单的代码。编译错误:
JavaApplication1类中的方法f不能应用于给出类型;
必填:Map<Person, List<? extends Dog>
发现:Map<Person, List<Dog>>
原因:实际参数Map<Person, List<Dog>>
无法通过方法调用转换转换为Map<Person, List<? extends Dog>
。
Map<Person, List<? extends Dog>
更通用,所以编译器应该能够转换?
此外:Map<Person, List<? extends Dog>> peopleDogList = A.<Person, List<Dog>>map();
不起作用。 ? extends Dog
表示继承Dog
或Dog
的对象,因此单词Dog
应该没问题?
答案 0 :(得分:13)
Map<Person, List<Dog>>
与Map<Person, List<? extends Dog>>
不兼容。在这种情况下,地图的值类型应为List<? extends Dog>
,而不是可转换为相同的值。但是,如果您使用Map<Person, ? extends List<? extends Dog>>
作为f
的参数,它就会起作用。
这是一个涉及更多基本类型的简单示例:
Map<String, List<?>> foo = new HashMap<String, List<Object>>(); // error
Map<String, ? extends List<?>> foo = new HashMap<String, List<Object>>(); // ok
OP询问为什么会出现这种情况。简单的答案是类型参数是不变的,而不是协变的。也就是说,给定Map<String, List<?>>
类型,地图的值类型必须完全 List<?>
,而不是类似于它的东西。为什么?想象一下,如果允许协变类型:
Map<String, List<A>> foo = new HashMap<>();
Map<String, List<?>> bar = foo; // Disallowed, but let's suppose it's allowed
List<B> baz = new ArrayList<>();
baz.add(new B());
bar.put("baz", baz);
foo.get("baz").get(0); // Oops, this is actually a B, not an A
哎呀,违反了foo.get("baz").get(0)
为A
的预期。
现在,假设我们以正确的方式做到了:
Map<String, List<A>> foo = new HashMap<>();
Map<String, ? extends List<?>> bar = foo;
List<B> baz = new ArrayList<>();
baz.add(new B());
bar.put("baz", baz); // Disallowed
在那里,编译器尝试将不兼容的列表放入foo
(通过别名bar
)。这就是? extends
是必需的原因。
答案 1 :(得分:0)
问题是您尝试将HashMap<Person, List<Dog>>
传递给期望Map<Person, List<? extends Dog>>
的方法。
编译器不允许您执行此操作的原因是您调用的方法可能会执行Map<Person, List<? extends Dog>>
上允许的操作,但HashMap<Person, List<Dog>>
上不允许这样做。例如,它可能会尝试向地图添加条目,其值为ArrayList<Rottweiler>
。这适用于Map<Person, List<? extends Dog>>
(假设Rottweiler
延伸Dog
),但不适用于任何Map<Person, List<Dog>>
。