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?
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).
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.
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.
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.
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 of A
instanceof B
is also an instanceof A
Since Java arrays are covariant:
B[]
is a subtype of A[]
instanceof B[]
is also an instanceof A[]
However, Java generics are invariant:
List<B>
is NOT a subtype of List<A>
instanceof List<B>
is NOT an instanceof List<A>
.Wildcards are used to make it more flexible while preserving type safety.
List<B>
is a List<? extends A>
List<Animal> animals = new ArrayList<Dog>()
?<E extends Number>
and <Number>
?If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With