Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the purpose behind wildcards and how are they different from generics?

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?

like image 269
rfgamaral Avatar asked May 27 '10 16:05

rfgamaral


People also ask

What is the use of wildcard in generics?

In generic code, the question mark (?), called the wildcard, represents an unknown type. The wildcard can be used in a variety of situations: as the type of a parameter, field, or local variable; sometimes as a return type (though it is better programming practice to be more specific).

Why do we need wildcard in Java?

The question mark (?) is known as the wildcard in generic programming. It represents an unknown type. The wildcard can be used in a variety of situations such as the type of a parameter, field, or local variable; sometimes as a return type.

What is the difference between bounded and unbounded wildcards in Java generics?

both bounded and unbounded wildcards provide a lot of flexibility on API design especially because Generics is not covariant and List<String> can not be used in place of List<Object>. Bounded wildcards allow you to write methods that can operate on Collection of Type as well as Collection of Type subclasses.

What is upper bounded wildcards in generics?

You can use an upper bounded wildcard to relax the restrictions on a variable. For example, say you want to write a method that works on List<Integer>, List<Double>, and List<Number>; you can achieve this by using an upper bounded wildcard.


2 Answers

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.

like image 65
Alexander Pogrebnyak Avatar answered Sep 21 '22 13:09

Alexander Pogrebnyak


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

  • 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>?
like image 30
polygenelubricants Avatar answered Sep 22 '22 13:09

polygenelubricants