带有ArrayList通配符的Java HashMap

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

HashMap<String, ArrayList> myMap = new HashMap<String, ArrayList>(); 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) 

错误消息是

类型为Example的方法foo(HashMap<?,ArrayList>)不适用于参数( HashMap<String,ArrayList> )。

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

我认为通过使用ArrayList (没有? extends ),我可以将函数限制为仅具有ArrayList值的HashMaps。

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

 public static  void printer(HashMap<K, ArrayList> list) { } 

这表明我认为ArrayList会起作用。 谁能解释这里的细微之处?

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

 List <= List // OK, right is subtype of left 

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

 List <= List> // FAIL 

这可以

 List> <= List> 

因为新的第一级? 。 如果ST亚型,则GG子类型G G 。 在S=List情况下应用它, T=List

  1. 类型HashMap>表示将某些未知(固定)类型的键映射到列表的映射,每个列都包含一些未知固定类型的元素

  2. 这种地图的具体实例将是,例如:

     new HashMap>(); 

    这是一个地图, 我们可以在其中添加任意ArrayLists作为值,对于我们从中获取的值(列表),我们对参数类型一无所知。

  3. 类型HashMap>表示从字符串到整数列表的映射 。 这是一个地图,我们只能将整数的ArrayLists作为值添加, 而不是任意的ArraysLists 。 因此,它不能是类型2的子类型(因为它允许少于它)。

    (类型1是2的超类型,它也允许键类型未知。)

  4. HashMap>类型HashMap> HashMap>表示从字符串到某种未知类型的映射,只知道它是ArrayList的子类型 。 在这样的映射中,我们不能插入任何东西(作为值),但是我们得到的所有值都保证是ArrayList类型,即一个未知的arraylist(可能是每个列表的另一个东西) 。 我们可以插入新的String键,但只能使用null值。

    类型2和类型3都是类型4的子类型(因为ArrayListArrayList满足extends ArrayList条件),但彼此不extends ArrayList

  5. HashMap> HashMap>就像4,但我们也不知道密钥类型。 这意味着我们不能对地图做任何事情,除了迭代它(或查找键的值 – get()接受一个Object参数,而不是K )并删除东西。 对于我们检索的值,我们只能迭代和删除东西,而不是插入甚至重新排序任何东西。 (即类型4是类型5的子类型。)

  6. 类型变量的方法参数类型HashMap>表示从某种类型K到某种类型V的列表的映射,其中K和V由方法的调用者决定 。 类型3显然适合这种情况(使用 ),因此您可以调用此方法。 您无法将新密钥放入地图中,因为您的方法不知道K是什么,但您可以将现有密钥映射到新值。 您可以使用new ArrayList() (并将这些元素作为值放入地图中),但是您只能将现有列表中的现有V对象放入这些列表中。 比5型还要多得多。


请注意:您应该使用更通用的类型MapList而不是HashMapArrayList作为您的方法,因为大多数情况下该方法适用于任何方法地图/列表的类型,并不关心具体的实现。 你也会用

 Map> myMap = new HashMap>(); 

声明并初始化您的变量。 (您仍然可以将ArrayList对象作为值。)

这很简单。 即使VHashMap的子类型, HashMap也不是HashMap的子类型。 (你已经知道了,对吧?)这里, VArrayListWArrayList 。 (重要的是它们是不同的。)是的, ArrayListArrayList的子类型,但这就是我们之前介绍的内容,即它无关紧要。 但是, HashMap HashMap的子类型HashMap 因为通配符而HashMap