I'd never heard about wildcars until a few days ago and after reading my teacher's Java book, I'm still not sure about what's it for and why would I need to use it.
Let's say I have a super class Animal
and few sub classes like Dog
, Cat
, Parrot
, etc... Now I need to have a list of anim开发者_C百科als, my first thought would be something like:
List<Animal> listAnimals
Instead, my colleagues are recommending something like:
List<? extends Animal> listAnimals
Why should I use wildcards instead of simple generics?
Let's say I need to have a get/set method, should I use the former or the later? How are they so different?
The wildcards do not make a lot of sense when you declare local variables, however they are really important when you declare a parameter for a method.
Imagine you have a method:
int countLegs ( List< ? extends Animal > animals )
{
int retVal = 0;
for ( Animal cur : animals )
{
retVal += cur.countLegs( );
}
return retVal;
}
With this signature you can do this:
List<Dog> dogs = ...;
countLegs( dogs );
List<Cat> cats = ...;
countLegs( cats );
List<Animal> zoo = ...;
countLegs( zoo );
If, however, you declare countLegs
like this:
int countLegs ( List< Animal > animals )
Then in the previous example only countLegs( zoo )
would have compiled, because only that call has a correct type.
Java generics are invariant.
Suppose we have B extends A
:
B
is a subtype ofA
- an
instanceof B
is also aninstanceof A
Since Java arrays are covariant:
B[]
is a subtype ofA[]
- an
instanceof B[]
is also aninstanceof A[]
However, Java generics are invariant:
List<B>
is NOT a subtype ofList<A>
- a
instanceof List<B>
is NOT aninstanceof List<A>
.
Wildcards are used to make it more flexible while preserving type safety.
- a
List<B>
is aList<? extends A>
References
- Java Tutorials/Generics
- Subtyping
- More fun with wildcards
Related questions
- Any simple way to explain why I cannot do
List<Animal> animals = new ArrayList<Dog>()
? - java generics (not) covariance
- What is the difference between
<E extends Number>
and<Number>
?
The difference between your 2 examples is simply that the first one is a list of generic/general animals - you can therefore add any type of animal to it, and any instance of a subclass of type Animal. (e.g. It can contain some dogs, some cats, some porcupines...) Whereas the second - List <? extends Animal>
- will be a list of one specific subtype of class animal. It can be any one you choose (this is set each time at runtime), but only one. It will either be a list of dogs, or a list of cats, or a list of turtles... etc.
You can store Dogs and Cats in a List<Animal>
. That is not where wildcards are needed.
Let's say you have a method that takes a list of animals:
void foo(List<Animal> animals) {
...
}
Now you can't pass the method a List of Dogs -- it only takes an argument of type List<Animal>
. You need a wildcard to make the method accept all kinds of Lists of Animals: List<Animal>
, List<Dog>
, List<Cat>
, ...
void foo(List<? extends Animal> animals) {
...
}
See
http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html
精彩评论