我想我问的是协变返回类型。我有一些生成的代码,我正在尝试扩展和使用。我们假设我有以下两个类:
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()方法,因为返回类型不匹配,尽管两个类都在同一方向上扩展。有人可以解释一下吗?
答案 0 :(得分:5)
您对co-variant
的理解是正确的,但不是.asasge不是。 List<SubChild>
与List<SuperChild>
考虑到这一点,List<Animals>
与List<Dogs>
不同,如果允许,事情可能会出现严重错误。 Dog
是Animal
,但如果允许分配如下:
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()
。