Why is passing a subclass to a bounded wildcard only allowed in certain places?
This following is from generics tutorials:
Say class R extends S,
public void addR(List<? extends S> s) {
s.add(0, new R()); // Compile-time error!
}
You should be able to figure out why the code above is disallowed. The type of the second parameter to s.add() is ? extends S -- an unknown subtype of S. Since we don't know what type it is, we don't know if it is a supertype of R; it might or might not be such a supertype, so it isn't safe to pass a R there.
I have read it a few times but still I don't quite understand why the following is an error
Given the List.add()'s signature
void add(int index, E element)
isn't it equivalent to
开发者_StackOverflow社区void add(int index, <? extends S> element) // just to explain the idea, not a valid syntax
why is it an error call add(0, new R()) R being an S?
Here's what the text in italics is referring to:
The parameter s
, of type List<? extends S>
, could be not just an instance of List<S>
or List<R>
, but also List<T>
where T
extends S
. In that case, even if R
also extends S
, R
does not necessarily extend T
(they could be, e.g. siblings in the class hierarchy). Since you can only put a value of type T
in such a collection, the compiler can't guarantee at compile time that putting an R
there would be safe.
To give a more concrete example, you can't add a Double
to a List<? extends Number>
, even though Double
extends Number
! That's because a variable of type List<? extends Number>
could, for example, be assigned a List<Integer>
at runtime, and adding a Double
to such a list is not allowed.
In fact, you can't actually call the add
method of a list declared to be List<? extends S>
, because at runtime the wildcard could always represent some subtype of S
that isn't a superclass of the thing you want to add. You can however read from such a list, since it's guaranteed that the wildcard is a subtype of S
, and therefore can be assigned to a variable of type S
:
public S getElement(List<? extends S> s) {
S result = s.get(0);
return result;
}
This general idea is referred to as PECS (producer-extends, consumer-super). Chapter 5 of Effective Java (conveniently enough, it's the sample chapter you can download from the book's website) has more to say about this and other subtleties of generics.
Figured this would be the simplest explanation
Class structure:
public class List<? extends S> {}
public class S {}
public class R extends S {}
public class T extends R {}
Code usage:
List<T> list = new List<T>();
in this case the following would be invalid:
list.add(new R());
精彩评论