参数在Java中扩展适当的参数

时间:2015-10-22 15:23:56

标签: java

我们说我有课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>添加模板来解决此问题?

2 个答案:

答案 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));