有人可以澄清Java(6)中的协变返回类型吗?

时间:2012-03-05 14:20:48

标签: java generics override covariance

我问的是协变返回类型。我有一些生成的代码,我正在尝试扩展和使用。我们假设我有以下两个类:

public class SuperParent
{
    public List<SuperChild> getList()
    {
        return new ArrayList<SuperChild>();
    }
}
public class SuperChild
{
}

现在,我想从这些中派生出新的类:

public class SubParent extends SuperParent
{
    public List<SubChild> getList()
    {
        return new ArrayList<SubChild>();
    }
}
public class SubChild extends SuperChild
{
}

问题是,显然我无法覆盖getList()方法,因为返回类型不匹配,尽管两个类都在同一方向上扩展。有人可以解释一下吗?

5 个答案:

答案 0 :(得分:5)

您对co-variant的理解是正确的,但不是.asasge不是。 List<SubChild>List<SuperChild>

不同

考虑到这一点,List<Animals>List<Dogs>不同,如果允许,事情可能会出现严重错误。 DogAnimal,但如果允许分配如下:

List<Dogs> dogs = new ArrayList<Dogs>();
List<Animals> animals = dogs; //not allowed.

然后当你添加一只猫时会发生什么?

animals.add(new Cat());

Dog dog = dogs.get(0); //fail

所以不允许这样做。

由于许多其他人的消息,请使用List<? extends SuperChild>作为返回类型来解决您的问题。

修改 对你上面的评论,如果你对超级班没有控制权,恐怕你什么都做不了。

答案 1 :(得分:3)

问题是,通用版List<SuperChild>List<SubChild>不兼容,因为如果您在getList()个实例上调用SubParent,而是通过{{1}接口,您将获得类型为SuperParent的返回值。这将允许您添加List<SuperChild> 的其他实例,即使该列表仅允许包含SuperChild的实例(根据SubChild中定义的返回类型)。

要进行此编译,请将返回类型更改为SubParent,即

List<? extends SuperChild>

这将允许您返回子类型列表,但不允许您将元素添加到使用超类型返回的列表中(即,您无法将元素添加到public class SuperParent { public List<? extends SuperChild> getList() { return new ArrayList<SuperChild>(); } }

答案 2 :(得分:2)

List<SubChild> List<SuperChild>

的子类

java的泛型中没有协变量。

因此,当您尝试共同变换返回类型时,它实际上是一个不同的类型,并且java不允许您完全更改它[因为它不安全]。

getList()中的SubParent方法应该返回List<SuperChild> [或ArrayList<SuperChild>,...]来解决此问题。

答案 3 :(得分:2)

正如其他人所指出的,List<SubChild>不是List<SuperChild>的子类。

根据您的目的,您可以使用泛型:

public class SuperParent<T extends SuperChild>
{
    public List<T> getList()
    {
        return new ArrayList<T>();
    }
}
public class SuperChild
{
}

public class SubParent extends SuperParent<SubChild>
{
    public List<SubChild> getList()
    {
        return new ArrayList<SubChild>();
    }
}
public class SubChild extends SuperChild
{
}

答案 4 :(得分:0)

想象一下这样的事情:

SubParent subParent = new SubParent();
SuperParent superParent = (SuperParent) subParent; // upcast is okay
List<SuperChild> list = superParent.getList();
list.add(new SuperChild());

最后一句话违反了SubParent合同。

修复方法是将SuperParent的getList合约更改为List<? extends SuperChild> getList()