I have a couple of questions about generic wildcards in Java:
What is the difference between List extends T>
and List super
If you have a class hierarchy A, B is a subclass of A, and C and D both are subclass of B like below
class A {}
class B extends A {}
class C extends B {}
class D extends B {}
Then
List<? extends A> la;
la = new ArrayList<B>();
la = new ArrayList<C>();
la = new ArrayList<D>();
List<? super B> lb;
lb = new ArrayList<A>(); //fine
lb = new ArrayList<C>(); //will not compile
public void someMethod(List<? extends B> lb) {
B b = lb.get(0); // is fine
lb.add(new C()); //will not compile as we do not know the type of the list, only that it is bounded above by B
}
public void otherMethod(List<? super B> lb) {
B b = lb.get(0); // will not compile as we do not know whether the list is of type B, it may be a List<A> and only contain instances of A
lb.add(new B()); // is fine, as we know that it will be a super type of A
}
A bounded wildcard is like ? extends B
where B is some type. That is, the type is unknown but a "bound" can be placed on it. In this case, it is bounded by some class, which is a subclass of B.
There may be times when you'll want to restrict the kinds of types that are allowed to be passed to a type parameter. For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.
Collection<? extends MyObject>
means that it can accept all object who have IS- A relationship with MyObject (i.e. any object which is a type of myObject or we can say any object of any subclass of MyObject) or a object of MyObject class.
For example:
class MyObject {}
class YourObject extends MyObject{}
class OurObject extends MyObject{}
Then,
Collection<? extends MyObject> myObject;
will accept only MyObject or children of MyObject(i.e. any object of type OurObject or YourObject or MyObject, but not any object of superclass of MyObject).
In general,
If a structure contains elements with a type of the form
? extends E
, we can get elements out of the structure, but we cannot put elements into the structure
List<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);
List<? extends Number> nums = ints;
nums.add(3.14); // compile-time error
assert ints.toString().equals("[1, 2, 3.14]");
To put elements into the structure we need another kind of wildcard called Wildcards with super
,
List<Object> objs = Arrays.<Object>asList(2, 3.14, "four");
List<Integer> ints = Arrays.asList(5, 6);
Collections.copy(objs, ints);
assert objs.toString().equals("[5, 6, four]");
public static <T> void copy(List<? super T> dst, List<? extends T> src) {
for (int i = 0; i < src.size(); i++) {
dst.set(i, src.get(i));
}
}
Josh Bloch also has a good explanation of when to use super
and extends
in this google io video talk where he mentions the Producer extends
Consumer super
mnemonic.
From the presentation slides:
Suppose you want to add bulk methods to
Stack<E>
void pushAll(Collection<? extends E> src);
– src is an E producer
void popAll(Collection<? super E> dst);
– dst is an E consumer
In your first question, <? extends T>
and <? super T>
are examples of bounded wildcards. An unbounded wildcard looks like <?>
, and basically means <? extends Object>
. It loosely means the generic can be any type. A bounded wildcard (<? extends T>
or <? super T>
) places a restriction on the type by saying that it either has to extend a specific type (<? extends T>
is known as an upper bound), or has to be an ancestor of a specific type (<? super T>
is known as a lower bound).
The Java Tutorials have some pretty good explanations of generics in the articles Wildcards and More Fun with Wildcards.
Generic wildcards are created to make methods that operate on Collection more reusable.
For example, if a method has a parameter List<A>
, we can only give List<A>
to this method. It is a waste for this method's funtion under some circumstances:
List<A>
, then we should be allowed to give List<A-sub>
to this method. (Because A-sub IS a A)List<A>
, then we should be allowed to give List<A-super>
to this method. (Because A IS a A-super)