带有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 extends List>> <= List>
因为新的第一级?
。 如果S
是T
亚型,则G
是G extends T>
子类型G extends T>
G extends T>
。 在S=List
情况下应用它, T=List>
。
-
类型
HashMap, ArrayList>>
表示将某些未知(固定)类型的键映射到列表的映射,每个列都包含一些未知固定类型的元素 。 -
这种地图的具体实例将是,例如:
new HashMap
>(); 这是一个地图, 我们可以在其中添加任意ArrayLists作为值,对于我们从中获取的值(列表),我们对参数类型一无所知。
-
类型
HashMap
表示从字符串到整数列表的映射 。 这是一个地图,我们只能将整数的ArrayLists作为值添加, 而不是任意的ArraysLists 。 因此,它不能是类型2的子类型(因为它允许少于它)。> (类型1是2的超类型,它也允许键类型未知。)
-
HashMap
类型> HashMap
> HashMap
表示从字符串到某种未知类型的映射,只知道它是> ArrayList>
的子类型 。 在这样的映射中,我们不能插入任何东西(作为值),但是我们得到的所有值都保证是ArrayList>
类型,即一个未知的arraylist(可能是每个列表的另一个东西) 。 我们可以插入新的String键,但只能使用null
值。类型2和类型3都是类型4的子类型(因为
ArrayList>
和ArrayList
满足extends ArrayList>
条件),但彼此不extends ArrayList>
。 -
HashMap, ? extends ArrayList>>
HashMap, ? extends ArrayList>>
就像4,但我们也不知道密钥类型。 这意味着我们不能对地图做任何事情,除了迭代它(或查找键的值 –get()
接受一个Object
参数,而不是K
)并删除东西。 对于我们检索的值,我们只能迭代和删除东西,而不是插入甚至重新排序任何东西。 (即类型4是类型5的子类型。) -
类型变量
的方法参数类型HashMap
表示从某种类型K到某种类型V的列表的映射,其中K和V由方法的调用者决定 。 类型3显然适合这种情况(使用>
),因此您可以调用此方法。 您无法将新密钥放入地图中,因为您的方法不知道K
是什么,但您可以将现有密钥映射到新值。 您可以使用new ArrayList
(并将这些元素作为值放入地图中),但是您只能将现有列表中的现有() V
对象放入这些列表中。 比5型还要多得多。
请注意:您应该使用更通用的类型Map
和List
而不是HashMap
和ArrayList
作为您的方法,因为大多数情况下该方法适用于任何方法地图/列表的类型,并不关心具体的实现。 你也会用
Map> myMap = new HashMap>();
声明并初始化您的变量。 (您仍然可以将ArrayList
对象作为值。)
这很简单。 即使V
是HashMap
的子类型, HashMap
也不是HashMap
的子类型。 (你已经知道了,对吧?)这里, V
是ArrayList
, W
是ArrayList>
。 (重要的是它们是不同的。)是的, ArrayList
是ArrayList>
的子类型,但这就是我们之前介绍的内容,即它无关紧要。 但是, HashMap
是 HashMap
的子类型HashMap
因为通配符而HashMap
。