Difference between <? super T> and <? extends T> in Java
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
In Java, generics are a well-established mechanism that allow programmers to enforce type safety while reducing the need for type casts. Two of the wildcard features provided by generics are <? super T> and <? extends T>. They serve different purposes in controlling how types are passed and manipulated in methods and classes.
Understanding <? super T>
The <? super T> wildcard is used to specify a lower bound for a generic type. This means that the type must be T or a superclass of T (including T itself). It is particularly useful for operations intended to write or insert data into a collection. Essentially, <? super T> means "capable of holding at least T."
Example: Using <? super T>
Consider a scenario where we have a list intended for objects of type Integer or any superclass of Integer (like Number or Object). You can use the <? super Integer> wildcard to ensure that the list can hold an Integer or types that an Integer could be assigned to:
In this example, List<? super Integer> can be List<Integer>, List<Number>, or List<Object>.
Understanding <? extends T>
Conversely, <? extends T> sets an upper bound for the wildcard and ensures that any type used is either T or a subclass of T. This is suitable when you need to read items from a collection, ensuring that every item you read is type-safe and no narrower types than T are used.
Example: Using <? extends T>
Imagine you need to process or read elements from a list of Number types or any subtype (like Integer, Double etc.):
Here, List<? extends Number> could be a List<Number>, List<Integer>, List<Double>, and so on.
Key Differences and When to Use
Here is a summary of the key differences between <? super T> and <? extends T>:
| Aspect | <? super T> | <? extends T> |
| Description | Lower-bounded wildcard; T or superclass. | Upper-bounded wildcard; T or subclass. |
| Primary Usage | Safe to insert T and its superclasses. | Safe to read T and treat as T. |
Example Types for T = Integer | List<Integer>, List<Number>, List<Object> | List<Integer>, List<Double>, etc. |
| Suitable Operations | Writing to lists, stacks, and more. | Reading from lists, processing elements, etc. |
Practical Considerations
When designing methods or classes that operate on collections of generics, choosing between <? super T> and <? extends T> depends largely on whether you need read-only access (<? extends T>) or write access (<? super T>). The former ensures that all derived elements are treated generically as type T, offering safety when fetching elements. The latter, however, is more flexible in terms of what can be added, but does not guarantee safety when retrieving elements unless cast explicitly (which may lead to ClassCastException).
Conclusion
Using <? super T> and <? extends T> appropriately can lead to more robust, flexible, and error-free generic programming. Understanding the nuances of each can greatly enhance the functionality and safety of your Java applications, making your code both more professional and maintainable.

