Generic Classes and Formal Type Parameters
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.
Why a Group Needs a Chosen Type
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 a group of buttons, another for a group of sliders, and so on, you can write a single generic class named ControlGroup. Its type parameter stands for the kind of component held in a group. The same class definition can then serve many purposes, and the only thing that changes from one use to the next is the type parameter.
This article follows one idea through the material: the type parameter is a placeholder that a caller fills in, and the author of the generic class decides what kinds of values may fill it. Keep that question in mind as you read. Who decides which types are allowed, and where is that decision written down?
One Class, Two Parameterized Types
The source describes a generic class that can represent a group of a chosen GUI component type. Two parameterized types come from the same definition: ControlGroup<JButton>, which represents a group of JButton objects, and ControlGroup<JSlider>, which represents a group of JSlider objects. The class definition is not copied or rewritten for each case. The formal type parameter inside the class is replaced by the actual type the caller supplies.
- T in the class header declares the formal type parameter.
- ControlGroup<
JButton> suppliesJButtonas the actual type argument. - ControlGroup<
JSlider> reuses the same class definition with a different actual type argument.
Read the diagram as a substitution. The definition still says ControlGroup<T>. When the caller writes ControlGroup<JButton>, every place where the class refers to T now refers to JButton. When the caller writes ControlGroup<JSlider>, the same places refer to JSlider instead. The class itself does not change; only the type that fills the placeholder changes.
What a Wildcard Actually Widens
Wildcard types are one tool for writing generic code. A wildcard lets a method work with collections of objects of various types, instead of being tied to a single element type. The method is written so that its parameter can refer to a collection whose element type varies, and the method body therefore does not depend on one specific element type. This is valuable when the same operation should apply to a list of strings, a list of numbers, or a list of components.
The source is explicit about the limitation. A wildcard does not restrict the types that are allowed as formal type parameters in a generic class or method definition. A wildcard can make a method more general, but it cannot tell the compiler that the type parameter must come from some particular family of types. A wildcard alone cannot provide that kind of restriction, and this is the gap that bounded types were introduced to fill.
Where the Restriction Must Live
The source frames the difference as a matter of responsibility. The author of a generic class decides what the class is meant to hold. A wildcard lets the author describe a method that is flexible about element types. 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 itself, every use of the class is held to it.
The comparison shows the key point of this article. A wildcard operates on the method's parameter and makes that parameter flexible. Only a bound declared on the type parameter, in the class or method definition, can restrict which types may be supplied as the formal type parameter.
Bounded Type Parameters in Practice
The source gives a hypothetical extension of the ControlGroup scenario to show the purpose of a bound. Suppose the author only wanted ControlGroup to hold components that can be placed on a screen as interactive controls. A wildcard would not express that requirement. A bounded type exists to state a restriction of exactly this kind on the type parameter in the class definition. The example is hypothetical; its role is to show what a restriction does, not to define a real Swing hierarchy.
Trace the hypothetical bound through the same substitution you saw earlier. ControlGroup<JButton> and ControlGroup<JSlider> are both admitted, because each type satisfies the restriction written in the definition. A supply such as String would not satisfy it, so the restriction rejects that use. The rejection comes from the definition, not from anything the caller chose to do in the method that receives the group.
Mistakes About Wildcards and Bounds
Common mistake Believing a wildcard limits which types a caller may pass as the formal type parameter
Why it failsThe source states that a wildcard does not restrict the types allowed as formal type parameters in a generic class or method definition. It makes a method's parameter flexible about element types.
Do this insteadIf the goal is to restrict the type parameter, declare a bound on the type parameter in the class or method definition.
Common mistake Thinking a bound is only a convenience for the method that uses it
Why it failsThe source says the restriction belongs to the definition itself, so every use of the class is held to it.
Do this insteadTreat a bound as part of the class contract. Every parameterization, such as ControlGroup<JButton>, must satisfy it.
Common mistake Treating wildcards and bounded types as interchangeable
Why it failsThe source notes that they address different concerns. Wildcards serve flexibility over collections; bounds serve restriction of type parameters.
Do this insteadAsk first whether the goal is flexibility over collections or restriction of the type parameter, then choose the tool that matches.
Common mistake Assuming ControlGroup<JButton> and ControlGroup<JSlider> are two separate classes
Why it failsThe source says both come from one class definition, with only the type parameter changing between uses.
Do this insteadThink of one class definition with a placeholder that each use fills in.
Choosing the Right Tool
A colleague writes a generic method whose parameter accepts a collection of any element type, and says this also ensures that the generic class it belongs to only holds interactive controls. Using the distinction from this article, explain which part of the code does the widening and which part, if any, could restrict the formal type parameter. What would you change to enforce the restriction?
Hints
- Ask whether the statement about any element type is about a method parameter or about a formal type parameter.
- Recall that the source says a wildcard does not restrict formal type parameters.
- The restriction must be declared where the type parameter is defined, so that every use of the class is held to it.
Key Takeaways
- A wildcard lets a method accept collections of objects of various types, but it does not restrict which types may be supplied as formal type parameters in a generic class or method definition.
- A bounded type parameter states a restriction on the types that may fill a formal type parameter, and that restriction belongs to the definition, so every use of the class must satisfy it.
- One generic class such as ControlGroup yields ControlGroup<
JButton> and ControlGroup<JSlider>; the class definition stays the same and only the type parameter changes. - Wildcards and bounds address different concerns: choose a wildcard for flexibility over collections, and a bound for restricting the type parameter.