您的位置:首页 > 编程语言 > Java开发

Java 泛型 list <?extends animal>和 list <Animal>

2016-12-04 08:49 267 查看
原文来自stakeoverflow     链接:http://stackoverflow.com/questions/2575363/generics-list-extends-animal-is-same-as-listanimal

The difference between 
List<Animal>
 and 
List<?
extends Animal>
 is this: 

With 
List<Animal>
,
you know what you have is definitely a list of animals. 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


Just a sidenote - the following would not be valid:
aL.peek().meow();//we can't do this, as it's not guar
4000
anteed that aL.peek() will be a Cat


Of course if we're absolutely certain aL.peek() is a cat, we can do this:
((Cat)aL.peek()).meow();//will generate a runtime error if aL.peek() is not a Cat


With 
List<?
extends Animal>
, you're making a statement about the type of list you're dealing with.

For example:
List<? extends Animal> L;


This is actually not a declaration of the type of object L can hold. It's a statement about what
kinds of lists L can reference.

For example, at this point,
L = aL;//remember aL is a List of Animals


would be something we could do.

But even after that assignment, all the compiler knows about L is that it is a List of [either Animal or a subtype of Animal]s

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 absolutely cannot add an Animal.

Why not? Well, let's see:
List<Goat> gL = new List<Goat>();//fine
gL.add(new Goat());//fine
gL.add(new Animal());//compiletime error


The reason the above doesn't work is we are attempting to cast an Animal as a Goat. That doesn't work, because what if after doing that we tried to make that Animal do a 'headbutt', like a goat would? We don't necessariliy know that the Animal can do that.

It is not. 
List<Animal>
 says
that the value which is assigned to this variable must be of "type" 
List<Animal>
.
This however doesn't mean that there must only be 
Animal
 objects,
there can be subclasses too.
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>
 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>
).

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".
This avoid some weird down casts if you have a list of some subclasses, but the method expects a list of the baseclass.
publid 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>
.
But if you wrote 
List<?
extends Number>
 you can pass 
List<Double>
 objects
even as they aren't 
List<Number>
 objects.
publid 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
 stuff.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  泛型 Java extends