我们说我有课Animal
和课Bear
,它扩展了课程Animal
。
现在在构造函数中,我的参数为Animal
:
public class Forest {
private List<Animal> animals;
public Forest(List<Animal> list) {
animals = list;
}
}
为什么我不能做那样的事情?
List<Bear> bears = new ArrayList<>();
new Forest(bears);
我认为Bear
是详细案例Animal
。
我是否可以通过向Forest<P extends Animal>
添加模板来解决此问题?
答案 0 :(得分:5)
您可以使用外卡
private List<? extends Animal> animals;
public Forest(List<? extends Animal> list) {
animals = list;
}
这使得列表包含任何种类的动物,甚至是不同类型的动物。
这将全部编译:
List<Bear> bears = new ArrayList<>();
new Forest(bears);
...
List<Animal> mix = new ArrayList<>();
mix.add(new Animal());
mix.add(new Bear());
new Forest(mix);
缺点是除了它们是动物外,你不会知道它的类型。
有关使用通配符以及何时使用extends
vs super
的时间和时间的规则,具体取决于您是否在集合中添加新元素。
参见Explanation of the get-put principle,有时也称为PECS,代表“Put Extends,Create Super”
修改强>
为了以后能够将其他动物添加到列表中,您必须更改动物列表字段以不使用通配符。但是,构造函数仍然可以使用通配符,但您应该创建一个从构造函数传递列表的新List对象。
这将有效:
private List<Animal> animals;
public Forest(Collection<? extends Animal> list) {
animals = new ArrayList<>(list);
}
public void add(Animal a){
animals.add(a);
}
public void addAll(Collection<? extends Animal> as){
animals.addAll(as);
}
然后再
List<Bear> bears = new ArrayList<>();
Forest forest = new Forest(bears);
forest.add(new Animal());
我还添加了addAll
方法,该方法也使用了通配符
//same mix and bears lists from before
Forest forest2 = new Forest(mix);
forest2.addAll(bears);
答案 1 :(得分:0)
您也可以使用此方法
public static <C,T extends C> List<C> convert(List<T> list) {
List<C> c = new ArrayList<>(list.size());
c.addAll(list);
return c;
}
new Forest(convert(bears));