Java Generics
Type Bounds
Wildcards
<? super E>
<? extends E>

What is a difference between ? super E and ? extends E?

Object-Oriented Design practice on Codemia

Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.

Practice OOD

In Java generics, the wildcard symbols <? super E> and <? extends E> play a significant role in defining variable bounds and flexibility for collections and method parameters. Understanding the differences between these two is essential for utilizing Java's generic types effectively.

Introduction to Generics

Generics allow for type safety in Java without the need to define a class for every data type. They enable classes, interfaces, and methods to operate on objects of various types while still providing compile-time type safety.

To understand the constraints introduced by <? super E> and <? extends E>, let's first review what they mean:

  1. <? extends E>: This wildcard allows you to use any class that either matches the type E or is a subclass of E.
  2. <? super E>: This wildcard allows you to use any class that matches the type E or is a superclass of E.

<? extends E>

The <? extends E> wildcard represents an upper bounded wildcard. It's used when you want to ensure that you're dealing with either E objects or objects from subclasses thereof.

Example

To illustrate this point, consider a list of numbers:

java
1public void processList(List<? extends Number> list) {
2    for (Number num : list) {
3        System.out.println(num);
4    }
5}

In the above example, the processList method can accept a list of type Number or any subclass, such as Integer, Double, or Float. The benefit here is that you can read items from the list — since you know they are at least type Number — but you cannot add new elements, as the exact type is not specified.

Key Points

  • Read Access: You can read elements as type E or its parent classes.
  • No Write Access: Writing elements to the collection is disallowed because the exact type cannot be guaranteed.
  • Common Use Cases: You see this in APIs where the data flows out of the collection.

<? super E>

The <? super E> wildcard signifies a lower bounded wildcard. This wildcard is useful when adding elements to a structure, enforcing that the structure can handle all objects of type E or any superclass thereof.

Example

Take a scenario where you are adding elements to a list:

java
1public void addElements(List<? super Integer> list) {
2    list.add(Integer.valueOf(1));
3    list.add(Integer.valueOf(2));
4    // The following line would cause a compile-time error:
5    // Number number = list.get(0);
6}

Here, the list can be of type Integer, Number, or Object since Integer is a subclass of both Number and Object. Although you can add Integer values to this list, read operations may not directly return the desired type Integer unless explicitly cast, as demonstrated by the commented-out line.

Key Points

  • Write Access: You can write into the collection because the type bounds are set from a lower limit down.
  • Read Restrictions: You cannot assume the type of the retrieved objects without casting.
  • Common Use Cases: This pattern is frequent in APIs where the elements are added to the collection.

Table of Key Differences

Aspect<? extends E><? super E>
Wildcard TypeUpper boundedLower bounded
UsageUse when you want to read from a structureUse when you want to write to a structure
Read/Write PermissionsRead permitted, write not permitted (additions)Write permitted, read requires casting
Type ConstraintsAny subclass of EE or any superclass of E
Typical Use CasesData consumptionData addition

Conclusion

Both <? super E> and <? extends E> provide ways to introduce flexibility and type safety into Java applications, but selecting the right one depends on whether you're primarily reading from or writing to a data structure. By effectively leveraging these wildcards, developers can create robust and flexible APIs that accommodate a wide variety of use cases.

Understanding these differences is crucial to mastering Java generics and ensuring that your code can efficiently and safely handle hierarchies of types.


Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Object-Oriented Design practice on Codemia

Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.

Practice OOD

All Rights Reserved.