Wildcard generics in Java provide flexibility in working with generic types by allowing unknown or partially constrained types in method parameters, return types, or fields. They are denoted by the ? symbol and are useful when you need to work with a range of types without specifying an exact type.
Important Concepts of Wildcard Generics
- Purpose: Wildcards allow methods or classes to operate on generic types with unknown or loosely defined type parameters, enhancing flexibility while maintaining type safety.
- Syntax: The ? represents an unknown type, used in places like List<?>, List<? extends T>, or List<? super T>.
- Use Cases: Common in APIs like collections, where methods need to accept a variety of generic types (e.g., List<?> for any list).
Types of Wildcards
- Unbounded Wildcard (?)
- Represents any type, equivalent to ? extends Object.
- Used when you don’t care about the specific type but need to work with the generic structure.
- Example: List<?> can hold a List<Integer>, List<String>, etc.
- Limitation: You can’t add elements (except null) because the type is unknown, but you can read as Object.
- Upper-Bounded Wildcard (? extends T)
- Restricts the type to T or its subtypes.
- Used for read-heavy operations (e.g., iterating over a list of numbers).
- Example: List<? extends Number> accepts List<Integer>, List<Double>, etc.
- Limitation: You can read elements as T (e.g., Number), but you can’t add elements (except null) due to type uncertainty.
- Lower-Bounded Wildcard (? super T)
- Restricts the type to T or its supertypes.
- Used for write-heavy operations (e.g., adding elements to a list).
- Example: List<? super Integer> accepts List<Integer>, List<Number>, or List<Object>.
- Limitation: You can add T or its subtypes, but reading yields Object unless you know the exact type.
Program
Demonstrating wildcard generics, focusing on upper- and lower-bounded wildcards
import java.util.ArrayList; import java.util.List; public class WildcardDemo { // Method using upper-bounded wildcard to sum numbers public static double sumList(List<? extends Number> list) { double sum = 0.0; for (Number num : list) { sum += num.doubleValue(); } return sum; } // Method using lower-bounded wildcard to add integers public static void addIntegers(List<? super Integer> list, int count) { for (int i = 1; i <= count; i++) { list.add(i); } } public static void main(String[] args) { // Upper-bounded wildcard example List<Integer> integers = new ArrayList<>(List.of(1, 2, 3)); List<Double> doubles = new ArrayList<>(List.of(1.5, 2.5, 3.5)); System.out.println("Sum of integers: " + sumList(integers)); // 6.0 System.out.println("Sum of doubles: " + sumList(doubles)); // 7.5 // Lower-bounded wildcard example List<Number> numbers = new ArrayList<>(); List<Object> objects = new ArrayList<>(); addIntegers(numbers, 3); addIntegers(objects, 2); System.out.println("Numbers list: " + numbers); // [1, 2, 3] System.out.println("Objects list: " + objects); // [1, 2] } } /* Sum of integers: 6.0 Sum of doubles: 7.5 Numbers list: [1, 2, 3] Objects list: [1, 2] */