参数化集合中的Java继承存在疑问

时间:2010-06-07 17:43:47

标签: java generics inheritance

很明显,父类的对象可以保存对子节点的引用,但是在参数化集合的情况下这不适用吗?

例如:

Car class is parent of Sedan

所以

public void doSomething(Car c){
    ...
}

public void caller(){
    Sedan s = new Sedan();
    doSomething(s);
}

显然有效

但是

public void doSomething(Collection<Car> c){
    ...
}

public void caller(){
    Collection<Sedan> s = new ArrayList<Sedan>();
    doSomething(s);
}

无法编译

有人可以指出原因吗?而且,如何实现这样一种场景,其中函数需要迭代父对象的集合,仅修改父类中存在的字段,使用父类方法,但调用方法(比如3种不同的方法)传递集合三种不同的亚型..

当然,如果我这样做,它编译得很好:

public void doSomething(Collection<Car> c){
    ...
}

public void caller(){
    Collection s = new ArrayList<Sedan>();
    doSomething(s);
}

2 个答案:

答案 0 :(得分:4)

使用

public void doSomething(Collection<? extends Car> c){}

或(如建议的那样)

public <T extends Car> void doSomething(Collection<T> c){}

这意味着Collection属于Car(或Car本身)的任何子类,而不是“它只是Car个实例的集合”

这是因为集合是不变的,不像数组,它们是协变。引用Effective Java

  

Covariant [..]表示如果SubSuper的子类型,则数组类型Sub[]Super[]的子类型。相反,泛型是不变的:对于任何两种不同的类型Type1Type2List<Type1>是一个子类型,也不是List<Type2>的超类型

答案 1 :(得分:2)

doSomething需要声明为doSomething(Collection<? extends Car> c)。以这种方式声明,您将无法向集合添加任何元素,因为您不知道该集合应包含的Car的特定子类。

这里的一般问题是,Collection<Sedan>根本不能被视为Collection<Car>的子类,因为您无法在Collection<Sedan>上执行Collection<Car>上的所有操作}。例如,您可以add SportsCarCollection<Car>,因为SportsCarCar。您无法将SportsCar添加到Collection<Sedan>,因为SportsCar不是Sedan