简体   繁体   English

泛型:列表<? extends Animal>与列表相同<Animal> ?

[英]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>列表中添加DoubleInteger对象,有或没有? extends ? extends stuff. ? extends东西。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么不能列出<!--? extends Animal-->替换为列表<animal> ?</animal> - Why can't List<? extends Animal> be replaced with List<Animal>? 是列表<dog>列表的子类<animal> ? 为什么 Java generics 不是隐式多态的?</animal></dog> - Is List<Dog> a subclass of List<Animal>? Why are Java generics not implicitly polymorphic? 为什么什么时候<t extends animal>选角名单<list<animal> > 列出<list<t> > 导致编译错误,但转换列表<animal>列出<t>引起警告? </t></animal></list<t></list<animal></t> - Why when <T extends Animal> casting List<List<Animal>> to List<List<T>> causes compilation error, but casting List<Animal> to List<T> causes warning? 将List <Animal>转换为List <Dog> - Casting List<Animal> to List<Dog> 公众有什么区别 <T extends Animal> void addAll(List <T> 动物)和public void addAll(List <Animal> 动物)? - What is the difference between public <T extends Animal> void addAll(List<T> animals) and public void addAll(List<Animal> animals)? 狗是动物,但清单 <Dog> 没有列出 <Animal> 。 如何在泛型/多态函数中安全使用它? - Dog is Animal but list<Dog> is not list<Animal>. How to use it safely in a generic/polymorphic function? 是否可以在没有演员的情况下从 Animal 列表中获取 Dog 列表? - Is it possible to get a list of Dog from a list of Animal without a cast? 是否可以使用类型参数 List 覆盖继承的方法<animal>与列表<dog> ?</dog></animal> - Is it possible to override an inherited method with type parameter List<Animal> with List<Dog>? Java集合:列表 <Animal> 老虎=新的ArrayList <Tiger> ()错误 - Java Collections: List<Animal> tiger = new ArrayList<Tiger>() WRONG 从一个子类型中检索<? extends Animal> - retrieving sub type from a <? extends Animal>
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM