【问题标题】:wildcard generics in HashSet constructorHashSet 构造函数中的通配符泛型
【发布时间】:2011-09-26 15:48:03
【问题描述】:

java HashSet 实现有一个构造函数:

public HashSet(Collection<? extends E> c) {
    map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
    addAll(c);
} 

为什么是Collection&lt;? extends E&gt; c?这还不够:Collection&lt;E&gt; c?

【问题讨论】:

    标签: java generics wildcard hashset


    【解决方案1】:

    这是因为当 HashMap 可以包含继承自 E 的对象时,因此您希望能够传递继承 E 的任何类型的对象集合,而不仅仅是 E。

    如果它是 Collection,那么您将无法传递 ArrayList&lt;F&gt;,例如 F 扩展 E。

    【讨论】:

      【解决方案2】:

      这里的概念叫做variance(协变,逆变)。

      假设你有以下两个类:

      class A {}
      class B extends A {}
      

      在这种情况下,您可以说B 的实例是A 的实例。也就是说,下面的代码是完全有效的:

      A instance = new B();
      

      现在,Java 中的泛型类默认情况下是不变的。这意味着 List&lt;B&gt; 不是 List&lt;A&gt;。也就是说,下面的代码不会编译:

      List<A> as = new ArrayList<B>(); // error - Type mismatch!
      

      但是,如果您有 B 的实例,请确保可以将其添加到 A 的列表中(因为 B 扩展了 A):

      List<A> as = new ArrayList<A>();
      as.add(new B());
      

      现在,假设您有一个通过使用 A 的实例来处理 A 列表的方法:

      void printAs(List<A> as) { ... }
      

      很想拨打以下电话:

      List<B> bs = new ArrayList<B>();
      printAs(bs); // error!
      

      但是,它不会编译!如果您想进行这样的调用,您必须确保参数List&lt;B&gt; 是方法预期类型的​​子类型。这是通过使用协方差来完成的:

      void printAs2(List<? extends A> as) { ... }
      List<B> bs = new ArrayList<B>();
      printAs2(bs);
      

      现在,此方法采用List&lt;? extends A&gt; 的实例,List&lt;B&gt; extends List&lt;? extends A&gt; 确实如此,因为B extends A。这就是协方差的概念。


      介绍完之后,我们可以回到你提到的HashSet的构造函数:

      public HashSet(Collection<? extends E> c) { ... }
      

      这意味着以下代码将起作用:

      HashSet<B> bs = new HashSet<B>();
      HashSet<A> as = new HashSet<A>(bs);
      

      之所以有效,是因为HashSet&lt;B&gt; is a HashSet&lt;? extends A&gt;

      如果构造函数被声明为HashSet(Collection&lt;E&gt; c),那么第二行将无法编译,因为即使HashSet&lt;E&gt; extends Collection&lt;E&gt;HashSet&lt;B&gt; extends HashSet&lt;A&gt;(不变)也不是真的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-12-28
        • 2010-10-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-06-10
        • 2011-07-17
        相关资源
        最近更新 更多