generics:列表<? 扩展Animal>与List <Animal>相同?

我只是想了解Javagenerics中的extends关键字。

List<? extends Animal> List<? extends Animal>意味着我们可以填充List任何对象 Animal

那么下面也不会有同样的意思:

 List<Animal> 

有人能帮我了解上述两者之间的区别吗? 对我来说这只是声音冗余而已。

谢谢!

List<Dog>List<? extends Animal>的子typesList<? extends Animal> List<? extends Animal> ,但不是List<Animal>的子types。

为什么List<Dog>不是List<Animal>的子types? 考虑下面的例子:

 void mySub(List<Animal> myList) { myList.add(new Cat()); } 

如果允许您将List<Dog>传递给此函数,则会出现运行时错误。


编辑:现在,如果我们使用List<? extends Animal> List<? extends Animal>反而会发生以下情况:

 void mySub(List<? extends Animal> myList) { myList.add(new Cat()); // compile error here Animal a = myList.get(0); // works fine } 

可以通过一个List<Dog>到这个函数,但是编译器意识到添加一些东西给列表可能会让你陷入困境。 如果你使用super而不是extends (允许你传递一个List<LifeForm> ),那么List<LifeForm>就是这样。

 void mySub(List<? super Animal> myList) { myList.add(new Cat()); // works fine Animal a = myList.get(0); // compile error here, since the list entry could be a Plant } 

这背后的理论是合作和反变换 。

我看到你已经接受了一个答案,但是我只想加上我的意见,因为我想我可以在这里得到一些帮助。

List<Animal>List<? extends Animal>的区别List<? extends Animal> List<? extends Animal>如下。


随着List<Animal> ,你知道你有什么是绝对的动物列表。 实际上它们并不一定完全是“动物” – 它们也可以是派生types。 例如,如果你有一个动物列表,那么一对夫妇可能是山羊,其中一些是猫,等等 – 是吗?

例如,这是完全有效的:

 List<Animal> aL= new List<Animal>(); aL.add(new Goat()); aL.add(new Cat()); Animal a = aL.peek(); a.walk(); // assuming walk is a method within Animal 

当然,以下几点是无效的:

 aL.peek().meow(); // we can't do this, as it's not guaranteed that aL.peek() will be a Cat 

List<? extends Animal> List<? extends Animal> ,你正在做一个关于你正在处理的列表types的声明。

例如:

 List<? extends Animal> L; 

这实际上不是对象L可以容纳的types的声明。 这是关于什么样的列表L可以参考的声明。

例如,我们可以这样做:

 L = aL; // remember aL is a List of Animals 

但是现在所有的编译器都知道L是一个[动物或动物亚型的列表]

所以现在以下是无效的:

 L.add(new Animal()); // throws a compiletime error 

因为我们所知道的,L可能是参考一个山羊名单 – 我们不能添加一个动物。

原因如下:

 List<Goat> gL = new List<Goat>(); // fine gL.add(new Goat()); // fine gL.add(new Animal()); // compiletime error 

在上面,我们试图把一只动物当成一只山羊。 那是行不通的,因为如果这样做之后我们试图让那只动物像山羊一样做一个“头撞”呢? 我们不一定知道动物可以做到这一点。

不是这样。 List<Animal>表示赋给这个variables的值必须是“type” List<Animal> 。 然而,这并不意味着只能有Animal对象,也可以有子类。

 List<Number> l = new ArrayList<Number>(); l.add(4); // autoboxing to Integer l.add(6.7); // autoboxing to Double 

你使用List<? extends Number> 如果您对获取Number对象的列表感兴趣,但是List对象本身不需要是List<Number>types,而是可以是任何其他子类列表(如List<Integer> ),那么List<? extends Number>构造。

这有时用方法参数来说“我想要一个Numbers列表,但我不在乎它是否只是List<Number> ,它也可以是List<Double> 。 如果你有一些子类的列表,这可以避免一些奇怪的下注,但是这个方法需要一个基类列表。

 public void doSomethingWith(List<Number> l) { ... } List<Double> d = new ArrayList<Double>(); doSomethingWith(d); // not working 

这不是因为您期望List<Number> ,而不是List<Double> 。 但是如果你写了List<? extends Number> List<? extends Number> ,即使它们不是List<Number>对象,也可以传递List<Double> List<Number>对象。

 public void doSomethingWith(List<? extends Number> l) { ... } List<Double> d = new ArrayList<Double>(); doSomethingWith(d); // works 

注意:这整个东西与列表本身中的对象的inheritance无关。 你还可以在List<Number>列表中添加DoubleInteger对象,有没有? extends ? extends东西。