如何使用通配符实例化泛型?

时间:2014-10-01 16:46:04

标签: java generics wildcard instantiation

让我们使用外卡研究一些通用的情况:

1

此代码

List<?> list = new ArrayList<?>();

生成以下错误:

required: class or interface without bounds
found:    ?

2

但是这个

List<?> list = new ArrayList< Set<?> >();

编译成功。

3

和此:

List<Set<?>> list = new ArrayList< Set<?> >();

也是成功的。

4

但是这个:

List<Set<Map<?,?>>> list = new ArrayList< Set<Map<String,String>> >();

产生

required: List<Set<Map<?,?>>>
found:    ArrayList<Set<Map<String,String>>>

5

List<Set<?>> list = new ArrayList< HashSet<?> >();

生成

required: List<Set<?>>
found:    ArrayList<HashSet<?>>

我对这些输出感到非常困惑。

我看到以下规律:

我可以仅在第一级上从右侧部分的左侧部分替换?,并且类型内部的类型应该相同&lt;&gt;只是?和?是禁止的。

但我不明白为什么?

您是否可以提供如何使用通配符实例化泛型的通用规则?

2 个答案:

答案 0 :(得分:3)

  1. 您无法使用通配符直​​接实例化类型。实例化时,type参数必须是实际类型,因此会生成编译器错误。
  2. 代码:

    List<?> list = new ArrayList<?>();
    
    1. 以下编译成功。
    2. 代码:

      List<?> list = new ArrayList< Set<?> >();
      

      您可以使用通配符作为类型参数的泛型类型参数,例如Set<?>,一组任何东西。此外,任何类型参数都将匹配左侧的通配符?

      1. 这也成功编译:
      2. 代码:

        List<Set<?>> list = new ArrayList< Set<?> >();
        

        类型参数匹配,?不能直接用于上面的(1)。

        1. 以下不编译:
        2. 代码:

          List<Set<Map<?,?>>> list = new ArrayList< Set<Map<String,String>> >();
          

          这是因为即使Map<String, String>Map<?, ?>List<Set<Map<String, String>>>也不是List<Set<Map<?, ?>>>。 Java泛型是不变的,这意味着类型参数必须匹配; &#34;是-a&#34;必须使用上限中的通配符显式指定relationship。例如。通过在左侧引入上限通配符来编译此更改。

          List<? extends Set<? extends Map<?,?>>> list = new ArrayList< Set<Map<String,String>> >();
          
          1. 以下内容的编译原因与上述(4)相同:
          2. 代码:

            List<Set<?>> list = new ArrayList< HashSet<?> >();
            

            即使HashSet<?>Set<?>,由于Java的不变泛型,ArrayList<HashSet<?>>也不是List<Set<?>>。在左边引入通配符作为上限也可以在这里工作:

            List<? extends Set<?>> list = new ArrayList< HashSet<?> >();
            

答案 1 :(得分:2)

  1. 您无法使用通配符进行实例化。您必须指定类型。 “?”不是一种类型。
  2. 这没关系,因为你给了List<?>一个类型Set<?>Set<?>是一种类型。
  3. 正确。 ArrayList<T>List<T>
  4. 的子类型
  5. 这就是事情变得丑陋的地方。右手不是左手的子类型,因为Java处理类型参数的方式很复杂。类型参数必须完全匹配,或者您必须使用协方差/逆变(<A extends B><A super B>内容)。 List<String>不是List<Object>的子类型。它的子类型List<? extends Object>List<?>
  6. 同上。如果您已将其声明为List<? extends Set<?>>,那么它将起作用。