您收到编译器错误的原因与您无法将Dog 添加到List<? extends Animal> 的原因相同——当引用变量的类型具有上限通配符时,您无法使用泛型参数调用方法。 map 变量的值类型参数可以引用与? extends Collection<String> 匹配的任何 类型,可能是HashMap<Integer, LinkedList<String>>。你可以在调用put之前合法地插入这一行:
map = new HashMap<Integer, LinkedList<String>>();
编译器不知道映射中真正存在的确切类型,因此它必须在编译时阻止您将 putting TreeSet<String> 作为映射的值,其值可能类似于LinkedList<String>.
对于map 中的值put(除了null),您必须删除通配符。
HashMap<Integer, TreeSet<String>> map =
new HashMap<Integer, TreeSet<String>>();
正如 JB Nizet 所评论的,如果您删除通配符但保留 Collection,您仍然可以输入任何 Collection 的值,例如 TreeSet。
HashMap<Integer, Collection<String>> map =
new HashMap<Integer, Collection<String>>();
(另外,菱形运算符可以简化这里的声明。)
针对添加到问题中的更改:
在这里,您使用了下限。
HashMap<Integer, ? super Collection<String>> map = new HashMap<Integer, TreeSet<String>>());
类型参数可以是Collection<String> 或任何超类型,例如Object。这不允许诸如TreeSet<String> 之类的子类型。 Java 的泛型是不变的。允许 Collection<String> 的任何变化的唯一原因是通配符。
HashMap<Integer, ? super Collection<String>> map = new HashMap<>();
map.put(1, new TreeSet<String>());
这是允许的,因为Collection<String> 的任何超类型都将匹配任何子类型作为参数。毕竟,TreeSet<String> 就是Object。 TreeSet<String> 可以是 put 作为 map 的值,无论是 HashMap<Integer, Object> 或 HashMap<Integer, Collection<String>>,还是介于两者之间的任何类型。编译器可以证明类型安全,所以它允许调用。