和<! - ?扩展E - >列表

时间:2009-12-15 11:01:29

标签: java generics

具有以下简单的类结构:

class A {
}

class B extends A {
}

class C extends B {
}

我正在创建一个ArrayList来保存先前创建的类的对象:

List<? extends A> list1 = new ArrayList<A>();
List<? extends B> list2 = new ArrayList<B>();
List<? extends C> list3 = new ArrayList<C>();

List<? super A> list4 = new ArrayList<A>();
List<? super B> list5 = new ArrayList<B>();
List<? super C> list6 = new ArrayList<C>();

对于每个列表,我正在尝试添加每个先前创建的类的1个对象:A,B,C。唯一可能的组合是:

  • 将类A,B,C的对象添加到list4

  • 将B类和C类的对象添加到list5

  • 将C类对象添加到列表list6中。 其余的尝试给出了编译器错误,例如:

  

方法添加(捕获#1-of?extends   A)类型列表不适用于   参数(A)

为什么我不能将A,B,C类的任何对象添加到list1 / 2/3? 为何... list4接受类A,B,C的对象,如果它们应该是A类的超类,因为list4是定义的吗?

5 个答案:

答案 0 :(得分:14)

“?extends A”表示“某种类型派生自A(或A本身)”。例如,List<ByteArrayOutputStream>List<? extends OutputStream>兼容 - 但您不应该将FileOutputStream添加到此类列表中 - 它应该是List<ByteArrayOutputStream>!你所知道的是,你从列表中获取的任何东西都是某种OutputStream

“?super A”表示“某种类型,它是A(或A本身)的超类”。例如,List<OutputStream>List<? super ByteArrayOutputStream>兼容。你绝对可以在这样的列表中添加ByteArrayOutputStream - 但如果你从列表中获取一个项目,你就无法真正保证它。

有关详情,请参阅Angelika Langer's Generics FAQ

答案 1 :(得分:4)

类型定义List<? extends A>不适用于可变列表 - Java泛型Java Generics Pdf 中给出的解释是

  

add()方法接受E类型的参数,即元素类型   采集。       当实际类型参数为?时,它代表某种未知类型。   任何参数       我们传递给add必须是这个未知类型的子类型。因为我们   不知道       什么类型,我们不能传递任何东西。

但是,当typedef为List<? super A>时,那么类型参数?隐式输入。

答案 2 :(得分:2)

List<? extends A> list1 

它是一个列表,其type元素可以是A的任何未知子类。例如,它可以是D子类。因此,你不能添加任何东西,它可能是错误的......

List<? super A> list4

它是一个列表,其类型元素可以是A,或者是A的超类(在这种情况下不存在,除了Object)。因此,您可以向其添加A对象,或者添加A的任何子类,例如B或C.

答案 3 :(得分:1)

这不起作用。

创建函数时应该使用<? extends T>哪个参数是某种类型的未知子类型的集合,并且您想要从该集合中获取对象:

int sum(Collection<? extends Integer> collection) {
    for (Integer : collection) {
        // do sth
    }
    // ...
}

您无法向此集合添加新项目,因为您不知道此集合包含哪种具体类型。您所知道的是,该类型扩展了Integer

如果要将<? super T>类型的新项目添加到集合并返回该集合,则使用T,但是您无法保证可以从中检索的内容,并且必须转换{的结果{1}}或检查其类型。您可以安全地添加get()类型和子类型的项目,并检索T类型的项目。

答案 4 :(得分:0)

List<? super B>允许您使用任何超类型B的列表,即list5 = new ArrayList&lt; A &gt;(); 或list5 = new ArrayList&lt; Object &gt;();

你可以安全地将B(和子类型)添加到使用B超类型的每个列表中,但是你不能添加任何超类型的B.想象一下:

public void myAdd(List<? super B> lst) {
  lst.add(new Object()) //this is a supertype of B (compile time error)
}
...
ArrayList<A> list = new ArrayList<A>();
myAdd(list); //tries to add Object to a list of type A