代码之家  ›  专栏  ›  技术社区  ›  David Koelle

如何将元素添加到通配符泛型集合?

  •  16
  • David Koelle  · 技术社区  · 18 年前

    为什么这个Java代码会出现编译器错误?

    1  public List<? extends Foo> getFoos()
    2  {
    3    List<? extends Foo> foos = new ArrayList<? extends Foo>();
    4    foos.add(new SubFoo());
    5    return foos;
    6  }

    • 第4行:“类型列表中的add(capture#1-of?extends Foo)方法<capture#1-of?extends Foo>不适用于参数(subfo)”

    更新:

    5 回复  |  直到 17 年前
        1
  •  32
  •   erickson    7 年前

    改用这个:

    1  public List<? extends Foo> getFoos()
    2  {
    3    List<Foo> foos = new ArrayList<Foo>(); /* Or List<SubFoo> */
    4    foos.add(new SubFoo());
    5    return foos;
    6  }
    

    一旦你将foos声明为 List<? extends Foo> ,编译器不知道添加子对象是安全的。如果一个 ArrayList<AltFoo> foos

        2
  •  20
  •   stites James    10 年前

    我只是想通过总结用类型或通配符实例化的列表参数的属性来添加到这个旧线程中。。。。

    当一个方法有一个作为列表的参数/结果时,类型实例化或通配符的使用将决定

    1. 可以作为参数传递给方法的列表类型
    2. 可以从方法结果填充的列表类型
    3. 可以写入方法中列表的元素类型

    List< Foo>

    1. 可以作为参数传递给方法的列表类型:
      • 列表<Foo>
    2. 可从方法结果填充的列表类型:
      • List< ? super Foo>
      • List< ? super SubFoo>
      • List< ? extends Foo>
      • List< ? extends SuperFoo>
    3. 可写入方法中列表的元素类型:
      • Foo
    4. 从方法中的列表中读取元素时可以填充的类型:
      • Object )

    参数/返回类型: 列表<?扩展Foo>

    1. 可以作为参数传递给方法的列表类型:
      • 列表<Foo>
      • List< Subfoo>
      • List< SubSubFoo>
      • 列表<?扩展Foo>
      • List< ? extends SubFoo>
      • List< ? extends SubSubFoo>
    2. 可从方法结果填充的列表类型:
      • 列表<?扩展SuperFoo>
      • List< ? extends SuperSuperFoo>
    3. 可写入方法中列表的元素类型:
    4. 从方法中的列表中读取元素时可以填充的类型:
      • 福 对象 )

    参数/返回类型: List<? super Foo>

    1. 可以作为参数传递给方法的列表类型:
      • 列表<Foo>
      • List< Superfoo>
      • List< SuperSuperFoo>
      • List< ? super SuperFoo>
      • List< ? super SuperSuperFoo>
      • 列表<?super Subfo>
      • List< ? super SubSubFoo>
      • 福 &超类
    2. 从方法中的列表中读取元素时可以填充的类型:
      • 福 对象 )

    解释/评论

    • 内部方法逻辑的需求驱动任何关于内部声明和构造的实际数据类型的额外决策(通常是次要考虑)
    • 使用 List<Foo> 如果调用方代码总是专注于操作Foo类,因为它最大限度地提高了读写的灵活性
    • List<? extends UpperMostFoo> 如果可能有许多不同类型的调用者,专注于操作不同的类(不总是Foo),并且Foo类型层次结构中有一个最上层的类,并且如果方法是内部写入列表,而调用者列表操作是读取。在这里,该方法可以在内部使用 List< UpperMostFoo> 并在返回之前向其添加元素 List< ? extends UpperMostFoo>
    • 如果可能有许多不同类型的调用者,专注于操作不同的类(不总是Foo),并且如果需要读写列表,并且Foo类型层次结构中只有一个最低级别的类,那么使用 List< ? super LowerMostFoo>
        3
  •  7
  •   Dov Wasserman Dov Wasserman    18 年前

    public List<Foo> getFoos() {
        List<Foo> foos = new ArrayList<Foo>();
        foos.add(new SubFoo());
        return foos;
    }
    

    “foos”变量的声明可以有通配符,但由于您知道确切的类型,因此在那里引用相同的类型信息更有意义。你现在看到的是,foos拥有Foo的某些特定子类型,但我们不知道是哪一种。可能不允许添加子对象,因为子对象不是“Foo的所有子类型”。将声明更改为“列表”<Foo>foos='解决了第二个编译错误。

        4
  •  2
  •   SCdF    18 年前

    以下方法可以很好地工作:

    public List<? extends Foo> getFoos() {
        List<Foo> foos = new ArrayList<Foo>();
        foos.add(new SubFoo());
        return foos;
    }
    
        5
  •  2
  •   zslevi    15 年前

    要了解泛型如何工作,请查看此示例:

        List<SubFoo> sfoo = new ArrayList<SubFoo>();
        List<Foo> foo;
        List<? extends Foo> tmp;
    
        tmp = sfoo;
        foo = (List<Foo>) tmp;