Java中的通用类型 - 高级多态

时间:2013-10-04 15:17:21

标签: java oop generics object polymorphism

我有3个简单的类如下:

public class ElementA {}
public class ElementB extends ElementA {}
public class ElementC extends ElementB {}

然后,如果我想创建,例如,只接受ElementA类的子类的泛型List,我可以将其声明为:

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

然后按如下方式使用它:

list.add(new ElementA());
list.add(new ElementB());
list.add(new ElementC());

这很好,可以编译没有错误。但是如果我想存储任何东西而不是ElementC或ElementB或ElementA,我会感到困惑。我声明如下列表:

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

我完全不能使用它,因为它只能存储空值。当我将List声明为(注意我正在使用'在家庭中间'的类)时,同样的事情发生了:

List<? extends ElementB>

为什么会这样?

3 个答案:

答案 0 :(得分:3)

问题是?的值在运行时是未知的。您必须替换具体的类/接口才能够做您想做的事。

如果你这样做:

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

你很好,因为ElementB 同时是 ElementA。同样代表ElementC

List<? extends ElementA>是有道理的,例如,如果你在类和子类中声明它,你可以用具体的东西替换类型参数。笨拙的例子:

public class SomeClass<T> {
    private List<? extends T> list;

    public void setList(List<? extends T> list) {
        this.list = list;
    }
}

public class SomeConcreteClass extends SomeClass<Integer> {

    public void doSomething() {
        List<Integer> list = new ArrayList<Integer>();
        setList(list);
    }
}

答案 1 :(得分:1)

List<ElementA>接受ElementAElementBElement C的实例。

List<ElementB>接受ElementBElement C的实例。

List<ElementC>接受ElementC

的实例

您的示例中没有使用通配符的原因。

List<? super ElementA>表示某种类型的列表,ElementA或超类。

List<? extends ElementB>表示某种类型的List,它是ElementB的子类。如果获取元素,它将是ElementB或子类,但它不知道该类是什么,因此无法确定您添加的元素是否正确类型,因为它是未知的(尽管它确实知道它是ElementB的子类)。

通配符有用,但你的例子不是其中之一。

答案 2 :(得分:0)

您可以像这样创建List

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

但是,让我们说,因为你仍然有效List这样

List<? extends ElementC> list = getElementCSubclassList(); // declared as returning a `List<ElementCSubclass>`

现在,编译器无法知道您的list对象包含ElementCSubclass个对象,它只能确保它包含某种类型的ElementC。因此,它不能让您使用任何期望实际泛型类型的方法。

想象一下

public class ElementCSubclass1 extends ElementC {}
public class ElementCSubclass2 extends ElementC {}
...
List<? extends ElementC> list = getElementCSubclass1List(); // declared as returning a `List<ElementCSubclass1>`

list.add(new ElementCSubclass2()); // this would immediately have to fail

编译器执行此操作,以便之前的情况永远不会发生。