原文来自stakeoverflow 链接:http://stackoverflow.com/questions/2575363/generics-list-extends-animal-is-same-as-listanimal
The difference between List
and List extends Animal>
is this:
With List
, 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 guaranteed 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
says that the value which is assigned to this variable must be of "type" List
. 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
but can any other list of subclasses (like List
).
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
, it can be a List
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
, not a List
. But if you wrote List extends Number>
you can pass List
objects even as they aren't List
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
list, with or without ? extends
stuff.