繁体   English   中英

Java中的泛型类型-高级多态

[英]Generic types in Java - advanced 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>

为什么这样?

问题在于? 在运行时未知。 您必须替换具体的类/接口才能执行所需的操作。

如果您这样做:

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

您很好,因为ElementB ElementA 同样代表ElementC

List<? extends ElementA> 如果您在类中声明它,并且在子类中可以将一些具体的东西替换为type参数,则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);
    }
}

List<ElementA>接受ElementAElementBElement C实例。

List<ElementB>接受ElementBElement C实例。

List<ElementC>接受ElementC实例。

您的示例中没有理由使用通配符。

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

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

通配符有一些用途,但您的示例不是其中之一。

您创建一个这样的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

编译器这样做是为了使以前的情况永远不会发生。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM