Wildcard Types in Generic Methods
Wildcard types let a method work with collections of objects of various types, but they do not restrict the types allowed as formal type parameters in a generic class or method definition.
One Class, Many Kinds of Group
Generic code is usually written once and then used with many different types. Imagine you want to create groups of GUI components. Rather than writing one class for button groups and another for slider groups, you can write a single generic class named ControlGroup. Its type parameter stands for the kind of component held in a group. This article follows that one scenario through the rest of the lesson, because it shows exactly where wildcards help and where they stop helping.
What do you think happens?
If both ControlGroup<JButton> and ControlGroup<JSlider> exist in a program, how many class definitions did the programmer have to write?
Reveal answer
One
Both parameterized types come from the same generic class definition. Only the type parameter changes from one use to the next, so the class itself is written once.
Tracing ControlGroup Through Two Type Arguments
The parameterized type ControlGroup<JButton> represents a group of JButton objects. The parameterized type ControlGroup<JSlider> represents a group of JSlider objects. In both cases the generic class is the same. The type argument in the angle brackets is what gets substituted for the type parameter when the class is used.
Following the type parameter through one class
Given a generic class ControlGroup whose type parameter stands for the component type held by the group, what does ControlGroup<JSlider> change and what stays the same?
- 1Identify the generic class
ControlGroup is defined once. Its definition contains a type parameter, which is a placeholder for a component type.
- 2Supply a type argument
Writing
JSliderin the angle brackets fills that placeholder with theJSlidertype. - 3Read the result
ControlGroup<
JSlider> is a group ofJSliderobjects. The class body is the same as it would be for ControlGroup<JButton>. Only the type parameter has been replaced.
The class definition is shared. The type argument determines which component type the group holds.
What a Wildcard Widens and What It Leaves Open
A wildcard type lets a method work with collections of objects of various types. It makes the method more general, because the method body does not depend on one specific element type.
Think of a wildcard as a way of widening what a method accepts. The method's parameter can refer to a collection whose element type varies. This is valuable when the same operation should apply to a list of strings, a list of numbers, or a list of components. The gain is real, but it answers only one design question. It does not answer which types a caller may supply for the formal type parameter of a generic class or method definition.
- The ? is a wildcard. It lets the parameter accept a List of any element type.
- The method body only relies on each element being an Object, so it works for any element type.
Where a Bound Enters the Definition
Bounded types were introduced to fill the gap a wildcard leaves. A bound is written in the definition itself, so it applies to the type parameter wherever the class is used. The author of a generic class decides what the class is meant to hold. A bounded type lets the author state that a type parameter may only be filled with types that satisfy the stated restriction. Because the restriction belongs to the definition, every use of the class is held to it.
The diagram above uses a hypothetical restriction. Suppose the author of ControlGroup wants it to hold only components that can be placed on a screen as interactive controls. The bound Component stands in for that requirement. JButton and JSlider satisfy it, so they may fill the type parameter. String does not, so a declaration such as ControlGroup<String> would be rejected by the restriction. The example is included only to show the role of a bound. The source does not give a specific bound for ControlGroup.
- The extends clause in the type parameter declaration is the bound.
- The restriction sits in the class definition, so ControlGroup<String> is rejected wherever it appears.
Common Misunderstandings About Wildcards and Bounds
Common mistake Believing a wildcard limits which types a caller can use for a class's type parameter
Why it failsA wildcard lets a method accept collections of varying element types. It does not restrict the types allowed as formal type parameters in a generic class or method definition.
Do this insteadIf the goal is to restrict which types may fill a type parameter, declare a bound in the definition.
Common mistake Believing a bound is only a convenience for a wildcard
Why it failsWildcards and bounded types address different concerns. The choice depends on whether the goal is flexibility over collections or restriction of type parameters.
Do this insteadAsk first whether you need flexibility for a method's parameter or a restriction on the type parameter. Then choose the matching tool.
Common mistake Thinking ControlGroup<JButton> and ControlGroup<JSlider> require two generic class definitions
Why it failsBoth come from one class definition. The type argument changes, not the class.
Do this insteadWrite the generic class once and supply different type arguments at each use.
Common mistake Assuming that a wildcard guarantees every element in a collection belongs to a particular family of types
Checking Your Reading of ControlGroup
A teammate says: 'I will use a wildcard in the declaration of ControlGroup so that only components can be stored in it.' Explain whether this achieves the goal, and state what mechanism the source describes for that purpose.
Hints
- Recall what the source says a wildcard does and does not restrict.
- Think about where a bound is written: in the method body, or in the definition of the type parameter.
Key Takeaways
- A single generic class such as ControlGroup can be used with different type arguments, such as ControlGroup<
JButton> and ControlGroup<JSlider>, without writing a new class definition. - A wildcard type lets a method accept collections of objects of various types, but it does not restrict the types allowed as formal type parameters in a generic class or method definition.
- A bounded type is written in the definition and states a restriction that every use of the class must satisfy.
- Wildcards and bounds solve different problems: flexibility over collections versus restriction of type parameters.