Wildcards (? extends / ? super)
Explore Java wildcards to master flexible and safe generic programming. Understand the difference between ? extends for reading and ? super for writing with collections. Learn the PECS principle to design reusable APIs while maintaining type safety and preventing runtime errors.
We often assume that because Integer is a subclass of Number, a List<Integer> must be a subtype of List<Number>. However, when we try to pass a list of integers to a method expecting a list of numbers, the compiler rejects it. This can be frustrating, especially when our logic seems perfectly sound. This restriction exists to protect memory safety, but it prevents us from writing reusable code that works across class hierarchies.
To solve this, Java provides wildcards, a powerful syntax that allows us to relax these strict type rules safely, enabling us to write flexible APIs that accept a range of types while preventing runtime errors.
The problem of invariance
In Java, generic types are invariant. This means that for any two distinct types Type1 and Type2, List<Type1> is neither a subtype nor a supertype of List<Type2>, even if Type1 inherits from Type2.
This rule prevents heap pollution. If Java allowed us to treat a List<Integer> as a List<Number>, we could attempt to add a Double to it (since a double is a number). However, the underlying list can only hold integers. By enforcing invariance, the compiler prevents this category of error entirely.
In the ...