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 ofAnimal
, possiblyAnimal
itself", which boils down to "some kind of animal". This is an example of a bounded wildcard, whereAnimal
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 thesuper
keyword instead ofextends
. The code<? super Animal>
, therefore, would be read as "an unknown type that is a supertype ofAnimal
, possiblyAnimal
itself". You can also specify an unknown type with an unbounded wilcard, which simply looks like<?>
. An unbounded wildcard is essentially the same as saying<? extends Object>
.
While
Cage<Lion>
andCage<Butterfly>
are not subtypes ofCage<Animal>
, they are in fact subtypes ofCage<? extends Animal>
:someCage = lionCage; // OK someCage = butterflyCage; // OKSo now the question becomes, "Can you add butterflies and lions directly tosomeCage
?". As you can probably guess, the answer to this question is "no".someCage.add(king); // compiler-time error someCage.add(monarch); // compiler-time errorIfsomeCage
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 intosomeCage
, 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);