views:

158

answers:

4

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 animals, 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?

+6  A: 

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.

froadie
+1 I thought it was the other way around, but it makes sense. Is like saying: *"This would be a list of I don't know what ( ? ) which is a subclass of Animal"* The question that comes later is, would it still be possible to declare it as: `List<Animal>` ? Or could I use a subclass of the subclass i.e. `List<Dog> l; l.add(new Bulldog() )`
OscarRyz
-1. List< ? extends Animal > can definitely be List< Animal >. The difference, you can only `get` Animals out of it and not put them back. The list itself still can contain a zoo ( or a farm ).
Alexander Pogrebnyak
+9  A: 

Java generics are invariant.

Suppose we have B extends A:

  • B is a subtype of A
  • an instanceof B is also an instanceof A

Since Java arrays are covariant:

  • B[] is a subtype of A[]
  • an instanceof B[] is also an instanceof A[]

However, Java generics are invariant:

  • List<B> is NOT a subtype of List<A>
  • a instanceof List<B> is NOT an instanceof List<A>.

Wildcards are used to make it more flexible while preserving type safety.

  • a List<B> is a List<? extends A>

References

Related questions

polygenelubricants
+3  A: 

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.

Alexander Pogrebnyak
@Nazgulled. As a corollary, for instance and local variables I recommend to always try to use a non-wildcarded generic. Sometimes you just don't have a choice, for example if the wildcarded generic is passed in the constructor and you need to store that reference, that's what you do. But if you are creating a generic variable, always try to assign it to non-wildcard declaration. You can always convert it to a wildcard later, but not otherwise without "unchecked" warning.
Alexander Pogrebnyak
+1  A: 

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

COME FROM