
1. Overview
In this article, we will learn the Java generics wildcard. To learn more about other Java topics, refer to these articles.
2. Java generics wildcard (PECS)
Java generics follow the “PECS” (Producer - extends and Consumer - super) principle.
- Producer - If you want to only retrieve the elements from a generic collection, use
extends
. - Consumer - If you want to only put elements into a generic collection, use
super
. - If you do both retrieve and put operations with the same collection, you shouldn’t use either
extends
orsuper
.
2. Java generics extends wildcard - Covariance
The Upper Bounded Wildcards restrict the unknown type to be a specific type or a subtype of that type and is represented using the extends
keyword.
List<? extends Number>
is an example of a bounded wildcard. The ?
stands for an unknown type which is in fact a subtype of Number
. Note that it could be Number
itself, or some subclass. It need not literally extend Number
. We can say that Number
is the upper bound of the wildcard.
The wildcard declaration of List<? extends Number> numberList
means that any of these are legal assignments:
List<? extends Number> numberList = new ArrayList<Number>(); // Number List<? extends Number> numberList = new ArrayList<Integer>(); // Integer extends Number List<? extends Number> numberList = new ArrayList<Double>(); // Double extends Number
2.1. Generics extends - Write operation
You can’t add any objects to the extends
generics including any subtype such as Integer
, Double
and super type Number
as well.
Look at the below code. We are trying to assign double
which results in the compilation error.
List<? extends Number> numberList = new ArrayList<Double>(); numberList.add(10.0); // error: incompatible types: double cannot be converted to CAP#1
The type of the numberList
is ? extends Number
, in the sense an unknown subtype of Number
. Since we don’t know what type it is and being unknown, we don’t know if it is an Integer
, Double
. Thus, it prevents assigning values to the extends
generics.
Even the below Number
assignment is not possible (what if it is a Double
).
List<? extends Number> numberList = new ArrayList<Number>(); numberList.add(10);
2.2. Generics extends - Read operation
You can read the values from the extends
generics and assign to Number
type. Since the values are definitely of type Number
, this is allowed.
public class MyClass { public static void main(String args[]) { List<? extends Number> numberList = getDoubleValues(); Number value = numberList.get(0); System.out.println(value); } private static ArrayList<Double> getDoubleValues() { ArrayList<Double> doubleList = new ArrayList<Double>(); doubleList.addAll(Arrays.asList(10.5, 9.5, 7.3)); return doubleList; } private static ArrayList<Integer> getIntValues() { ArrayList<Integer> intList = new ArrayList<Integer>(); intList.addAll(Arrays.asList(10, 9, 7)); return intList; } }
However, you can’t assign to subtype variables such as Double
or Integer
. The type of the numberList
is ? extends Number
, in the sense an unknown subtype of Number
. Since we don’t know what type it is and being unknown, we can’t assign to subtypes.
public static void main(String args[]) { List<? extends Number> numberList = getDoubleValues(); Double value = numberList.get(0); // error: incompatible types: CAP#1 cannot be converted to Double System.out.println(value); }
3. Java Generics super
wildcard
A lower bounded wildcard restricts the unknown type to be a specific type or a super type of that type.
We express a lower bounded wildcard using the wildcard character (‘?’), following by the super
keyword, followed by its lower bound: <? super A>
.
The wildcard declaration of List<? super Integer> numberList
means that any of these are legal assignments:
List<? super Integer> numberList = new ArrayList<Integer>(); // Integer List<? super Integer> numberList = new ArrayList<Number>(); // Number is a superclass of Integer List<? super Integer> numberList = new ArrayList<Object>(); // Object is a superclass of Integer
3.1. Generics super - Read operation
The type of the numberList
is ? super Integer
, in the sense, an unknown supertype of Integer
. Since we don’t know what type it is and being unknown, we don’t know if the super type is a Number
or Object
.
You can’t read the values and assign to Number
or Integer
as numberList
could be holding Number
or Object
super type.
List<? super Integer> numberList = getIntValues(); Number value = numberList.get(0); // error: incompatible types: CAP#1 cannot be converted to Number System.out.println(value);
As we know, it is legal to assign subtype value to a super type. As the Object
class doesn’t extend any supertype and Number
or Integer
are subtypes of an Object
, you can retrieve the list value to an Object
instance.
Though numberList
holds Integer
or Number
, both are subtypes of Object
.
public class MyClass { public static void main(String args[]) { List<? super Integer> numberList = getIntValues(); Object value = numberList.get(0); System.out.println(value); } private static ArrayList<Integer> getIntValues() { ArrayList<Integer> intList = new ArrayList<Integer>(); intList.addAll(Arrays.asList(10, 9, 7)); return intList; } }
3.2. Generics super - Write operation
You can add an Integer
or subclass of Integer
to the numberList
.
List<? super Integer> numberList = new ArrayList<Object>(); numberList.add(50); // allowed System.out.println(numberList.get(0));
However, you can’t add Double
, Number
or Object
to the numberList
.
List<? super Integer> numberList = new ArrayList<Object>(); Number number = 10; numberList.add(number); // error: incompatible types: Number cannot be converted to CAP#1 System.out.println(numberList.get(0));
4. Conclusion
To sum up, we have learned the Java generics wildcard. You can find code samples in our GitHub repository.