2011-07-06 42 views
4

我有一个HashMap其中的值的ArrayList,和我想要写一个函数来接受这些包含HashMap的一般情况Java的HashMap的ArrayList中与通配符

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) 

的错误消息是

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

为什么我需要扩展ArrayList的通配符?

我以为有ArrayList<?>(没有? extends),我可以限制函数只有HashMaps与ArrayList值。

我也知道,下面的一般方法的工作原理:

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

其行为我怎么想ArrayList<?>会工作。有人能解释这里的微妙之处吗?

+0

要么告诉我们'foo'生成的确切的编译器错误,或者给我们一个导致错误的'foo'里面的代码的例子。实际上,这两条信息都会有很大帮助 –

+0

在我的机器上工作 –

+0

'类型Example中的foo(HashMap >)方法不适用于参数(HashMap >)' –

回答

6

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

List<?> <= List<String> // OK, right is subtype of left 

但请记住,它只能在第1级,没有更深的

List<List<?> <= List<List<String>> // FAIL 

这是因为新的第一级?的罚款

List<? extends List<?>> <= List<List<String>> 

。 如果ST的亚型,G<S>G<? extends T>的亚型。适用于S=List<String>,T=List<?>

+0

您对此有任何引用吗?我确实证实了这种情况,但我只是好奇它在哪里被记录。 –

+0

@Bala http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html#Wildcards –

+0

好的。也发现了一个类似的答案与大量的参考文献http://stackoverflow.com/questions/3575681/cant-cast-to-to-unspecific-nested-type-with-generics/3575895#3575895 –

1
  1. 类型HashMap<?, ArrayList<?>>指约地图它映射一些未知的(固定的)的键键入列表,每一个都具有一些未知的固定式的元件。

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

    new HashMap<String, ArrayList<?>>(); 
    

    这是一个图,其中我们可以添加任意的ArrayList作为值,和值(列表),我们得到了其中我们不知道有关参数类型的任何信息。

  3. 类型HashMap<String, ArrayList<Integer>>意味着从字符串到整数列表列表的映射。这是一张我们只能添加Integer ArrayList作为值的映射,不是任意ArraysLists。因此,它不能是类型2的子类型(因为它允许小于它)。

    (类型1是超类型2,它也可以让密钥类型不明。)

  4. 类型HashMap<String, ? extends ArrayList<?>>装置从串的映射到一些未知类型,其仅已知的ArrayList<?>子类型。在这样的地图中,我们不能插入任何东西(作为值),但是我们从中得到的所有值都是ArrayList<?>,即一个未知数组的列表列表(可能是每个列表的另一个列表)。我们可以插入新的String键,但只能使用null值。

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

  5. HashMap<?, ? extends ArrayList<?>>就像4,但我们也不知道密钥类型。这意味着除了迭代它之外(或者查找键的值 - get()需要Object参数,而不是K)并删除内容,我们无法真正对地图执行任何操作。对于我们检索的值,我们只能迭代和删除东西,不能插入甚至重新排序。 (IE类型4是5类型的子类型)

  6. 的方法,参数类型HashMap<K, ArrayList<V>>与类型变量<K, V>装置从一些K型地图以某种类型V,其中K和V是由呼叫者决定列表的方法。类型3显然适用于此(与<String, Integer>),因此您可以调用此方法。由于您的方法不知道什么是K,但您可以将新键映射到新值,但您可以将现有键映射到新值。您可以使用new ArrayList<V>()(并将这些元素作为值放入地图中),但您只能将现有列表中的现有V对象放入这些列表中。不过比类型更可能很多5.


只是一个侧面说明:您应该使用更普遍的类型Map<K,V>List<E>代替HashMap<K,V>ArrayList<E>为你的方法,因为大多数肯定的方法将适用于任何类型的地图/列表,并不关心具体的实现。你也可以使用

Map<String, List<Integer>> myMap = new HashMap<String, List<Integer>>(); 

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

0

这很简单。 HashMap<K, V>不是HashMap<K, W>的子类型,即使VW的子类型。 (你已经知道了吧?)这里,VArrayList<Integer>,而WArrayList<?>。 (重要的是它们是不同的。)是的,ArrayList<Integer>ArrayList<?>的子类型,但这是我们之前提到的,即它是无关紧要的。但是,由于通配符,HashMap<K, V>HashMap<K, ? extends W>的子类型。