Because it might only allow objects of type B
.
A classic question, answered a million of times. Non-intuitive, but also not a design bug of Java.
Here is the classic example: let A
be Fruit
.
Can I put an Apple
into a Set<? extends Fruit>
?
No, because it could be a Set<Banana>
which obviously must not contain apples.
? extends Fruit
says some specific kind of fruit, and not "any kind of fruit". Then it would be a Set<Fruit>
which indeed can take any kind of Fruit.
As a rule of thumb:
- when putting
? super Fruit
is convenient. It takes "at least" fruits
- when getting
? extends Fruit
is convenient. It may return only one kind of fruit, but they will all be fruit.
Consider this method:
public static double computeAverage(Collection<? extends Number> col) {
double sum = 0.;
for (Number n : col) {
sum += n.doubleValue();
}
return sum / n.size();
}
This method can work with List<Integer>
. Because it does not put Double
into the list, but only takes Number
objects out.
public static void put(Collection<? super Number> col, Number n) {
col.put(n);
}
Here, we have the opposite case. We need a list that accepts arbitrary numbers (otherwise, we could not put the unspecific number in it). It may accept more, though:
put(new List<Object>(), (Double) 1.);
is valid, because I may put doubles into a list of Objects.
But the compiler correctly prevents put( new List<Integer>(), (Double) 1.)
.
It can get much messier than that:
public static <I,O> void transfer(Collection<? extends I> input,
Collection<? super O> output,
Converter<? super I, ? extends O> converter) {
for (I inobj : input) {
O outobj = converter.convert(inobj);
output.put(outobj);
}
}
But the compiler may be unable to figure out I
and O
automatically for you every time.