Java Wildcards Explained
Introduction
Java wildcards are a powerful feature of generics that allow flexibility when working with parameterized types.
Understanding wildcards helps you write more reusable and type-safe code, especially when dealing with collections.
Generics enable types (classes and interfaces) to be parameters when defining classes, interfaces, and methods.
What Are Wildcards in Java?
Wildcards in Java generics are represented by the question mark symbol (?). They act as placeholders for an unknown type.
They allow you to specify a range of acceptable types rather than a single specific type.
- Used in generic type arguments to increase flexibility.
- Can be unbounded or bounded (upper or lower).
- Help in writing methods that can operate on different types safely.
Types of Wildcards
There are three main types of wildcards in Java generics: unbounded, upper bounded, and lower bounded.
| Wildcard Type | Syntax | Description | Example |
|---|---|---|---|
| Unbounded Wildcard | <?> | Represents any type. | List<?> list = new ArrayList<String>(); |
| Upper Bounded Wildcard | <? extends T> | Represents a type that is T or a subtype of T. | List<? extends Number> nums; |
| Lower Bounded Wildcard | <? super T> | Represents a type that is T or a supertype of T. | List<? super Integer> ints; |
Unbounded Wildcards
The unbounded wildcard <?> matches any type. It is useful when you want to specify that a method can accept any generic type.
However, you cannot add elements to a collection declared with an unbounded wildcard because the exact type is unknown.
- Used when the type parameter does not matter.
- Allows reading elements as Object type.
- Prevents adding elements except null.
Upper Bounded Wildcards
Upper bounded wildcards restrict the unknown type to be a specific type or a subtype of that type.
This is useful when you want to read items from a collection and ensure they are at least of a certain type.
- Syntax: <? extends T>
- Allows reading items as type T.
- Prevents adding items except null.
Lower Bounded Wildcards
Lower bounded wildcards restrict the unknown type to be a specific type or a supertype of that type.
This is useful when you want to add items to a collection safely.
- Syntax: <? super T>
- Allows adding items of type T or its subtypes.
- Reading items returns Object type.
Practical Examples of Wildcards
Let's look at some practical examples demonstrating how wildcards are used in Java.
Example: Using Unbounded Wildcard
This method prints elements of any list, regardless of its type.
Example: Using Upper Bounded Wildcard
This method calculates the sum of numbers in a list of Number or its subclasses.
Example: Using Lower Bounded Wildcard
This method adds integers to a list that can accept Integer or its supertypes.
Examples
public void printList(List<?> list) {
for (Object elem : list) {
System.out.println(elem);
}
}This method accepts a list of any type and prints each element.
public double sumNumbers(List<? extends Number> list) {
double sum = 0.0;
for (Number num : list) {
sum += num.doubleValue();
}
return sum;
}This method sums elements of a list that contains Number or its subclasses.
public void addIntegers(List<? super Integer> list) {
list.add(10);
list.add(20);
}This method adds Integer values to a list that can accept Integer or its supertypes.
Best Practices
- Use unbounded wildcards when the type parameter is irrelevant for the method logic.
- Use upper bounded wildcards when you only need to read from a generic collection.
- Use lower bounded wildcards when you need to add elements to a generic collection.
- Avoid mixing wildcards unnecessarily to keep code readable.
- Prefer specific types when possible for clarity and type safety.
Common Mistakes
- Trying to add elements to a collection declared with an unbounded or upper bounded wildcard.
- Misunderstanding covariance and contravariance concepts related to wildcards.
- Using wildcards when a concrete generic type would be more appropriate.
- Ignoring compiler warnings related to unchecked operations with wildcards.
Hands-on Exercise
Identify Wildcard Usage
Given several method signatures using generics, identify which wildcard type is used and explain why.
Expected output: Correct identification and explanation of wildcard types.
Hint: Look for ?, ? extends, and ? super in the signatures.
Write a Method Using Upper Bounded Wildcard
Write a method that accepts a list of any subclass of Number and returns the average of its elements.
Expected output: A method that calculates and returns the average as a double.
Hint: Use <? extends Number> and iterate over the list to compute the average.
Interview Questions
What is the purpose of wildcards in Java generics?
InterviewWildcards provide flexibility by allowing unknown types in generic type arguments, enabling methods to operate on a range of types safely.
What is the difference between <? extends T> and <? super T>?
Interview<? extends T restricts the unknown type to T or its subclasses (upper bounded), useful for reading. <? super T> restricts to T or its supertypes (lower bounded), useful for adding.
Can you add elements to a List<?>?
InterviewNo, you cannot add elements to a List<?> except for null because the exact type is unknown.
Summary
Java wildcards enhance the flexibility of generics by allowing unknown types with certain bounds.
Unbounded wildcards accept any type, upper bounded wildcards restrict to a type and its subclasses, and lower bounded wildcards restrict to a type and its supertypes.
Understanding when and how to use each wildcard type helps write safer and more reusable code.
FAQ
Why can't I add elements to a collection declared with <?> or <? extends T>?
Because the exact type is unknown or could be a subtype, adding elements could violate type safety, so the compiler prevents it.
When should I use <? super T> wildcard?
Use <? super T> when you want to add elements of type T or its subtypes to a collection.
Are wildcards mandatory in Java generics?
No, wildcards are optional but useful for flexibility when you don't want to specify exact generic types.
