You can use unbounded wildcards, bounded wildcards, or lower-bound wildcards to specify a range for a generic type. What are wildcard generic types and why are they needed? The code below gives an example to
demonstrate the needs. The example defines a generic max method for finding the maximum in a stack of numbers (lines 15–25). The main method creates a stack of integer objects, adds three integers to the stack, and invokes the max method to find the maximum number in the stack.
The program above has a compile error in line 11 because intStack is not an instance of GenericStack. Thus, you cannot invoke max(intStack).
The fact is that Integer is a subtype of Number, but GenericStack is not a subtype of GenericStack. To circumvent this problem, use wildcard generic types. A wildcard generic type has three forms: ? and ? extends T, as well as ? super T, where T is a generic type.
The first form, ?, called an unbounded wildcard, is the same as ? extends Object. The second form, ? extends T, called a bounded wildcard, represents T or a subtype of T. The third form, ? super T, called a lower-bound wildcard, denotes T or a supertype of T.
You can fix the error by replacing line 15 in the code above as follows:
public static double max(GenericStack<? extends Number> stack) {
<? extends Number> is a wildcard type that represents Number or a subtype of Number, so it is legal to invoke max(new GenericStack()) or max(new GenericStack()).
The code below shows an example of using the ? wildcard in the print method that prints objects in a stack and empties the stack. <?> is a wildcard that represents any object type. It is equivalent to <? extends Object>. What happens if you replace GenericStack<?> with GenericStack? It would be wrong to invoke print(intStack), because intStack is not an instance of GenericStack. Please note that GenericStack is not a subtype of GenericStack, even though Integer is a subtype of Object.
When is the wildcard <? super T> needed? Consider the example in the code below. The example creates a stack of strings in stack1 (line 6) and a stack of objects in stack2 (line 7), and invokes add(stack1, stack2) (line 11) to add the strings in stack1 into stack2. GenericStack<? super T> is used to declare stack2 in line 15. If <? super T> is replaced by , a compile error will occur on add(stack1, stack2) in line 11, because stack1’s type is GenericStack and stack2’s type is GenericStack. <? super T> represents type T or a supertype of T. Object is a supertype of String.
This program will also work if the method header in lines 15 is modified as follows:
public static <T> void add(GenericStack<? extends T> stack1,
GenericStack<T> stack2)
The inheritance relationship involving generic types and wildcard types is summarized in Figure below. In this figure, A and B represent classes or interfaces, and E is a generic type parameter.