很明显,父类的对象可以保存对子节点的引用,但是在参数化集合的情况下这不适用吗?
例如:
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);
}
答案 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 [..]表示如果
Sub
是Super
的子类型,则数组类型Sub[]
是Super[]
的子类型。相反,泛型是不变的:对于任何两种不同的类型Type1
和Type2
,List<Type1>
是一个子类型,也不是List<Type2>
的超类型
答案 1 :(得分:2)
doSomething
需要声明为doSomething(Collection<? extends Car> c)
。以这种方式声明,您将无法向集合添加任何元素,因为您不知道该集合应包含的Car
的特定子类。
这里的一般问题是,Collection<Sedan>
根本不能被视为Collection<Car>
的子类,因为您无法在Collection<Sedan>
上执行Collection<Car>
上的所有操作}。例如,您可以add
SportsCar
到Collection<Car>
,因为SportsCar
是Car
。您无法将SportsCar
添加到Collection<Sedan>
,因为SportsCar
不是Sedan
。