Trail: Learning the Java Language
Lesson: Generics
Wildcards
Home Page > Learning the Java Language > Generics

Wildcards

Earlier we mentioned that English is ambiguous. The phrase "animal cage" can reasonably mean "all-animal cage", but it also suggests an entirely different concept: a cage designed not for any kind of animal, but rather for some kind of animal whose type is unknown. In generics, an unknown type is represented by the wildcard character "?".

To specify a cage capable of holding some kind of animal:

Cage<? extends Animal> someCage = ...;

Read "? extends Animal" as "an unknown type that is a subtype of Animal, possibly Animal itself", which boils down to "some kind of animal". This is an example of a bounded wildcard, where Animal forms the upper bound of the expected type. If you're asked for a cage that simply holds some kind of animal, you're free to provide a lion cage or a butterfly cage.


Note: It's also possible to specify a lower bound by using the super keyword instead of extends. The code <? super Animal>, therefore, would be read as "an unknown type that is a supertype of Animal, possibly Animal itself". You can also specify an unknown type with an unbounded wildcard, which simply looks like <?>. An unbounded wildcard is essentially the same as saying <? extends Object>.


While Cage<Lion> and Cage<Butterfly> are not subtypes of Cage<Animal>, they are in fact subtypes of Cage<? extends Animal>:

someCage = lionCage;      // OK
someCage = butterflyCage; // OK

So now the question becomes, "Can you add butterflies and lions directly to someCage?". As you can probably guess, the answer to this question is "no".

someCage.add(king);    // compiler-time error
someCage.add(monarch); // compiler-time error

If someCage is a butterfly cage, it would hold butterflies just fine, but the lions would be able to break free. If it's a lion cage, then all would be well with the lions, but the butterflies would fly away. So if you can't put anything at all into someCage, is it useless? No, because you can still read its contents:

void feedAnimals(Cage<? extends Animal> someCage) {
    for (Animal a : someCage)
        a.feedMe();
}

Therefore, you could house your animals in their individual cages, as shown earlier, and invoke this method first for the lions and then for the butterflies:

feedAnimals(lionCage);
feedAnimals(butterflyCage);

Or, you could choose to combine your animals in the all-animal cage instead:

feedAnimals(animalCage);

Problems with the examples? Try Compiling and Running the Examples: FAQs.
Complaints? Compliments? Suggestions? Give us your feedback.

Previous page: Subtyping
Next page: Type Erasure