带有ArrayList通配符的Java HashMap

Kev*_*vin 4 java generics wildcard arraylist hashmap

我有一个HashMap,其值是ArrayLists,我正在尝试编写一个函数来接受这些HashMaps的泛型实例

HashMap<String, ArrayList<Integer>> myMap = new HashMap<String, ArrayList<Integer>>();
public static void foo(HashMap<?, ArrayList<?>> a) {}
public static void bar(HashMap<?, ? extends ArrayList<?>> a) {}

// Compilation Failure!
foo(myMap);

// This works, but why do I need ? extends ArrayList
bar(myMap)
Run Code Online (Sandbox Code Playgroud)

错误消息是

foo(HashMap<?,ArrayList<?>>)类型中的方法Example不适用于arguments(HashMap<String,ArrayList<Integer>>).

为什么我需要为extends ArrayList使用通配符?

我认为通过拥有ArrayList<?>(没有? extends),我可以将函数限制为仅具有ArrayList值的HashMaps.

我也知道以下通用方法有效:

public static <K,V> void printer(HashMap<K, ArrayList<V>> list) { }
Run Code Online (Sandbox Code Playgroud)

这表现我的想法ArrayList<?>会起作用.有人能解释这里的细微之处吗?

irr*_*ble 6

通配符语法是故意设计的(错误)引导人们相信它匹配任何类型.这适用于简单的情况

List<?> <= List<String> // OK, right is subtype of left
Run Code Online (Sandbox Code Playgroud)

但请记住,它只适用于第一级,而不是更深

List<List<?> <= List<List<String>>  // FAIL
Run Code Online (Sandbox Code Playgroud)

这可以

List<? extends List<?>> <= List<List<String>>
Run Code Online (Sandbox Code Playgroud)

因为新的第1级?.如果S是子类型T,G<S>则是子类型G<? extends T>.适用于,S=List<String>以及T=List<?>.