[英]Generics : List<? extends Animal> is same as List<Animal>?
I am just trying to understand the extends
keyword in Java Generics.我只是想了解 Java 泛型中的
extends
关键字。
List<? extends Animal>
List<? extends Animal>
means we can stuff any object in the List
which IS A Animal
List<? extends Animal>
意味着我们可以填充List
任何对象,它是一个Animal
then won't the following also mean the same thing:那么以下是否也意味着同样的事情:
List<Animal>
Can someone help me know the difference between the above two?有人可以帮我了解上述两者之间的区别吗? To me
extends
just sound redundant here.对我来说,在这里
extends
只是听起来多余。
Thanks!谢谢!
List<Dog>
is a subtype of List<? extends Animal>
List<Dog>
是List<? extends Animal>
List<? extends Animal>
, but not a subtype of List<Animal>
. List<? extends Animal>
,但不是List<Animal>
的子类型。
Why is List<Dog>
not a subtype of List<Animal>
?为什么
List<Dog>
不是List<Animal>
的子类型? Consider the following example:考虑以下示例:
void mySub(List<Animal> myList) {
myList.add(new Cat());
}
If you were allowed to pass a List<Dog>
to this function, you would get a run-time error.如果允许您将
List<Dog>
传递给此函数,则会出现运行时错误。
EDIT: Now, if we use List<? extends Animal>
编辑:现在,如果我们使用
List<? extends Animal>
List<? extends Animal>
instead, the following will happen: List<? extends Animal>
相反,将发生以下情况:
void mySub(List<? extends Animal> myList) {
myList.add(new Cat()); // compile error here
Animal a = myList.get(0); // works fine
}
You could pass a List<Dog>
to this function, but the compiler realizes that adding something to the list could get you into trouble.您可以将
List<Dog>
传递给该函数,但编译器意识到向列表中添加内容可能会给您带来麻烦。 If you use super
instead of extends
(allowing you to pass a List<LifeForm>
), it's the other way around.如果您使用
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
}
The theory behind this is Co- and Contravariance .这背后的理论是协变和逆变。
With List<Animal>
, you know what you have is definitely a list of animals.使用
List<Animal>
,您知道您拥有的绝对是动物列表。 It's not necessary for all of them to actually be exactly 'Animal's - they could also be derived types.所有这些都没有必要实际上完全是“动物的”——它们也可以是派生类型。 For example, if you have a List of Animals, it makes sense that a couple could be Goats, and some of them Cats, etc - right?
例如,如果您有一个动物列表,那么一对夫妇可能是山羊,其中一些是猫,等等——对吗?
For example this is totally valid:例如,这是完全有效的:
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
Of course, the following would not be valid:当然,以下将是无效的:
aL.peek().meow(); // we can't do this, as it's not guaranteed that aL.peek() will be a Cat
With List<? extends Animal>
用
List<? extends Animal>
List<? extends Animal>
, you're making a statement about the type of list you're dealing with. List<? extends Animal>
,您正在声明您正在处理的列表类型。
For example:例如:
List<? extends Animal> L;
This is actually not a declaration of the type of object L can hold .这实际上不是L 可以容纳的对象类型的声明。 It's a statement about what kinds of lists L can reference.
这是关于 L 可以引用哪些类型的列表的声明。
For example, we could do this:例如,我们可以这样做:
L = aL; // remember aL is a List of Animals
But now all the compiler knows about L is that it is a List of [either Animal or a subtype of Animal]s但是现在编译器所知道的关于 L 的所有信息是它是一个[或者是 Animal 或者是 Animal 的子类型] 的列表
So now the following is not valid:所以现在以下内容无效:
L.add(new Animal()); // throws a compiletime error
Because for all we know, L could be referencing a list of Goats - to which we cannot add an Animal.因为就我们所知,L 可能指的是山羊列表——我们不能向其中添加动物。
Here's why:原因如下:
List<Goat> gL = new List<Goat>(); // fine
gL.add(new Goat()); // fine
gL.add(new Animal()); // compiletime error
In the above, we're trying to cast an Animal as a Goat.在上面,我们尝试将 Animal 转换为 Goat。 That doesn't work, because what if after doing that we tried to make that Animal do a 'headbutt', like a goat would?
那是行不通的,因为如果在这样做之后我们试图让那个 Animal 像山羊那样做“头撞”呢? We don't necessarily know that the Animal can do that.
我们不一定知道 Animal 可以做到这一点。
It is not.它不是。
List<Animal>
says that the value which is assigned to this variable must be of "type" List<Animal>
. List<Animal>
表示分配给这个变量的值必须是“类型” List<Animal>
。 This however doesn't mean that there must only be Animal
objects, there can be subclasses too.然而,这并不意味着必须只有
Animal
对象,也可以有子类。
List<Number> l = new ArrayList<Number>();
l.add(4); // autoboxing to Integer
l.add(6.7); // autoboxing to Double
You use the List<? extends Number>
您使用
List<? extends Number>
List<? extends Number>
construct if you are interest in an list which got Number
objects, but the List object itself doesn't need to be of type List<Number>
but can any other list of subclasses (like List<Integer>
).如果您对包含
Number
对象的列表感兴趣,则List<? extends Number>
构造,但 List 对象本身不需要是List<Number>
类型,但可以是任何其他子类列表(如List<Integer>
)。
This is sometime use for method arguments to say "I want a list of Numbers
, but I don't care if it is just List<Number>
, it can be a List<Double>
too" .这有时用于方法参数说“我想要一个
Numbers
列表,但我不在乎它是否只是List<Number>
,它也可以是List<Double>
” 。 This avoid some weird down casts if you have a list of some subclasses, but the method expects a list of the baseclass.如果您有一些子类的列表,这可以避免一些奇怪的向下转换,但该方法需要一个基类的列表。
public void doSomethingWith(List<Number> l) {
...
}
List<Double> d = new ArrayList<Double>();
doSomethingWith(d); // not working
This is not working as you expecting List<Number>
, not a List<Double>
.这不像您期望的那样工作
List<Number>
,而不是List<Double>
。 But if you wrote List<? extends Number>
但是如果你写
List<? extends Number>
List<? extends Number>
you can pass List<Double>
objects even as they aren't List<Number>
objects. List<? extends Number>
您可以传递List<Double>
对象,即使它们不是List<Number>
对象。
public void doSomethingWith(List<? extends Number> l) {
...
}
List<Double> d = new ArrayList<Double>();
doSomethingWith(d); // works
Note: This whole stuff is unrelated to inheritance of the objects in the list itself.注意:整个内容与列表本身中对象的继承无关。 You still can add
Double
and Integer
objects in a List<Number>
list, with or without ? extends
您仍然可以在
List<Number>
列表中添加Double
和Integer
对象,有或没有? extends
? extends
stuff. ? extends
东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.