泛型 : 列表<?扩展动物>与列表相同<动物>?
我只是试图理解Java泛型中的关键字。extends
List<? extends Animal>
意味着我们可以将任何对象塞进其中 IS AList
Animal
那么下面的内容就不也是一回事了:
List<Animal>
有人可以帮我知道上述两者之间的区别吗?对我来说,这里听起来是多余的。extends
谢谢!
我只是试图理解Java泛型中的关键字。extends
List<? extends Animal>
意味着我们可以将任何对象塞进其中 IS AList
Animal
那么下面的内容就不也是一回事了:
List<Animal>
有人可以帮我知道上述两者之间的区别吗?对我来说,这里听起来是多余的。extends
谢谢!
List<Dog>
是 的子类型,但不是 的子类型。List<? extends Animal>
List<Animal>
为什么不是 的子类型?请考虑以下示例:List<Dog>
List<Animal>
void mySub(List<Animal> myList) {
myList.add(new Cat());
}
如果允许您将 a 传递给此函数,则会收到运行时错误。List<Dog>
编辑:现在,如果我们改用,将发生以下情况:List<? extends Animal>
void mySub(List<? extends Animal> myList) {
myList.add(new Cat()); // compile error here
Animal a = myList.get(0); // works fine
}
您可以将 a 传递给此函数,但编译器意识到向列表中添加某些内容可能会给您带来麻烦。如果你使用而不是(允许你传递一个),那就反过来了。List<Dog>
super
extends
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<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> L;
这实际上不是L可以持有的对象类型的声明。这是关于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
在上面,我们试图将动物塑造成山羊。这是行不通的,因为如果在这样做之后,我们试图让那只动物做一个“头屁股”,就像山羊一样呢?我们不一定知道动物可以做到这一点。