为什么要尝试编译
public class GenericsFail {
public static void main(String[] args) {
accept(new HashMap<String, List<String>>());
}
public static void accept(Map<String, List<?>> multiMap) {}
}
给出错误
GenericsFail.java:7: error: method accept in class GenericsFail cannot be applied to given types;
accept(new HashMap<String, List<String>>());
^
required: Map<String,List<?>>
found: HashMap<String,List<String>>
reason: actual argument HashMap<String,List<String>> cannot be converted to Map<String,List<?>> by method invocation conversion
仅当通配符未嵌套在List
内时才允许使用通配符。
答案 0 :(得分:13)
原因是?
中的List<?>
可能是“任何”,但每个Map
条目中的不同“任何”。也就是说,它会在一个条目中接受List<String>
,在另一个条目中接受List<Integer>
。
但是你传入的Map
在每个条目中都有{em>相同类型的List
,所以类型不是以相同的方式绑定,也不是相同的自由度。
“修复”是将类型锁定为特定类型,但仍然是“任何” - 只需相同“每个条目中的任何*,通过键入方法:
public static <T> void accept(Map<String, List<T>> multiMap) // complies
或者如果您的方法确实不需要知道哪个类型,请使用通配符来包装类型:
public static void accept(Map<String, ? extends List<?>> multiMap) // compiles
这最后一个版本有效,因为列表的类型虽然是通配符,但固定为未知,但一致,在调用时键入。
我发现键入的版本更容易阅读(和代码),如果您稍后决定您的方法需要知道类型,那么该类型是可供使用的。
答案 1 :(得分:4)
更一般
void accept(Map<String, ? extends List<?>> multiMap)
答案 2 :(得分:2)
以下是编译器无法接受此参数的简短示例:
public static void main(String[] args) {
//if this would be accepted here ...
accept(new HashMap<String, List<String>>());
}
public static void accept(Map<String, List<?>> multiMap) {
//this is valid considering the type of multiMap parameter,
//but would not work with the actual passed parameter.
multiMap.put("test", new ArrayList<Integer>());
}