🏆 What Are Wildcards (?
) in Java?
Wildcards allow you to use unknown types in generics. They are useful when working with collections of different but related types.
Types of Wildcards in Java
Wildcard | Meaning | Example |
---|---|---|
? (Unbounded) | Accepts any type | List<?> list = new ArrayList<String>(); |
? extends T (Upper Bounded) | Accepts T or any subclass of T | List<? extends Number> list = new ArrayList<Integer>(); |
? super T (Lower Bounded) | Accepts T or any superclass of T | List<? super Integer> list = new ArrayList<Number>(); |
✅ 1. Unbounded Wildcard (?
)
- Use Case: When the type doesn’t matter (read-only operations).
- Example:
public static void printList(List<?> list) {
for (Object item : list) {
System.out.println(item);
}
}
List<String> names = List.of("Alice", "Bob");
List<Integer> numbers = List.of(1, 2, 3);
printList(names); // Works
printList(numbers); // Works
Rules:
- You can’t add elements to a
List<?>
(exceptnull
) because the type is unknown. - Only reading is allowed.
✅ 2. Upper Bounded Wildcard (? extends T
)
- Use Case: When you want to accept
T
or any of its subclasses but ensure safe reading. - Example:
public static double sumList(List<? extends Number> list) {
double sum = 0;
for (Number num : list) {
sum += num.doubleValue(); // Safe: We know it’s at least a Number
}
return sum;
}
List<Integer> intList = List.of(1, 2, 3);
List<Double> doubleList = List.of(1.5, 2.5, 3.5);
System.out.println(sumList(intList)); // Works
System.out.println(sumList(doubleList)); // Works
Rules:
- ✅ Reading is allowed (
Number num = list.get(i);
) - ❌ Writing is NOT allowed (
list.add(10);
won’t compile!)
✅ 3. Lower Bounded Wildcard (? super T
)
- Use Case: When you want to accept
T
or any of its superclasses, ensuring safe writing. - Example:
public static void addNumbers(List<? super Integer> list) {
list.add(10); // Allowed
list.add(20); // Allowed
// list.add(3.14); // ERROR: Only Integers or their subclasses allowed
}
List<Integer> intList = new ArrayList<>();
List<Number> numList = new ArrayList<>();
addNumbers(intList); // Works
addNumbers(numList); // Works
Rules:
- ✅ Writing is allowed (
list.add(new Integer(10));
) - ❌ Reading is limited (
Object obj = list.get(i);
but NOTInteger num = list.get(i);
)
🤔 When to Use Which Wildcard?
Use Case | Wildcard to Use |
---|---|
Read-only access to unknown type | ? (Unbounded) |
Reading from a list of unknown subtypes | ? extends T (Upper Bounded) |
Writing to a list of unknown supertypes | ? super T (Lower Bounded) |
🔥 Quick Mnemonic:
- Producer (
extends
) — Use? extends T
for reading.- “If it produces, it extends.”
- Example:
List<? extends Number> list
→ You can read Numbers, but not add anything.
- Consumer (
super
) — Use? super T
for writing.- “If it consumes, it super.”
- Example:
List<? super Integer> list
→ You can add Integers, but only read Objects.
🏁 Final Thoughts
Wildcards make Java generics more flexible while keeping type safety. They help when working with collections of different but related types and let you enforce safe read/write access.
Would you like to see more real-world examples or need further clarifications? 😊