I don't get the actual practical use case of the wildcard character ?
in Java, when using it with extends
or super
.
The official Oracle Java documentation shows an example of adding numbers to a list and sum them up:
private static double sumOfList(List<? extends Number> list) {
double sum = 0.0;
for (Number number : list) {
sum += number.doubleValue();
}
return sum;
}
From my understanding List<? extends Number> list
does not mean "a list of instances of Number objects and objects of possible sub-classes of Number" but instead "a list of objects of a single type, which have to be or extend the type Number". That's all fine.
Until I tried this code:
List<Number> numberList = new ArrayList<Number>();
numberList.add(Integer.valueOf(123));
numberList.add(Double.valueOf(2.34));
numberList.add(Float.valueOf(3.45f));
The instances can be added to the Number list through an implicit upcast to number references. And that list of numbers can then be used with the sumOfList method as shown above. But the elements would not be of a single type. So why would anyone use extends
with ?
anyways?
The other thing that I am not getting is the use of the wildcard character with super. It is fine, that you can define the lower bound of a type. The offical Oracle documentation shows this example:
public static void addNumbers(List<? super Integer> list) {
for (int i = 1; i <= 10; i++) {
list.add(i);
}
}
Thing is, this works great for a simple thing like adding numbers to a list. But the code shown also works with lists like this:
List<Object> list = new ArrayList<Object>();
list.add(Integer.valueOf(123));
list.add(Double.valueOf(2.34));
list.add(new Person("John", "Doe"));
So as long as one would call methods, that would do anything useful with actual numbers like - I dunno - arithmetical operations the code would probably work fine. But when it comes to the John Doe entry, code meant for numbers would fail.
So can anyone clarify the actual practical use of the extends
and super
keywords in combination with the ?
operator?
So why would anyone use
extends
with?
anyways?
Because you may not have a List<Number>
to pass to it. For example, you can pass a List<Integer>
, a List<BigInteger>
etc to sumOfList
.
If you hadn't declared it as accepting a List<? extends Number>
, but instead as accepting a List<Number>
, you could only pass a List<Number>
to it - List<Integer>
isn't a subtype of List<Number>
.
In terms of the addNumbers
method: you simply need some kind of List
to which it is safe to add instances of Integer
(or subtypes [of which there are none, because it is final], or null
).
That's all List<? super Integer>
means: it's safe to add instances of Integer
to that.
It's safe to pass a List<Object>
to that method, because all Integer
s are Object
s, so it's safe to add Integer
s to that list.
Again, if you'd declared the method as accepting a List<Object>
(or a List<Integer>
), that would be all you could pass to it: a List<Object>
(or a List<Integer>
, respectively). You couldn't pass it, say, a List<Number>
.
So can anyone clarify the actual practical use of the
extends
andsuper
keywords in combination with the?
operator?
The practical use of wildcards is to increase the flexibility of API methods, as illustrated above: it allows you to declare a single method that takes a range of related types as inputs.
You can also use wildcards in outputs, but this should be avoided, because the wildcard ends up in the type of the value at the call site, and just generally hangs around looking messy and confusing.