I have a couple of questions about generic wildcards in Java:
What is the difference between
List<? extends T>
andList<? super T>
?What is a bounded wildcard and what is an unbounded wildcard?
I have a couple of questions about generic wildcards in Java:
What is the difference between List<? extends T>
and List<? super T>
?
What is a bounded wildcard and what is an unbounded wildcard?
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.
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.
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
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));
}
}
Pre Requirements
public class A { }
public class B extends A { }
public class C extends A { }
List<A> listA = new ArrayList<A>();
List<B> listB = new ArrayList<B>();
The problem
listB = listA; //not compiled
listA = listB; //not compiled
listB = listA;
In listA you can insert objects that are either instances of A, or subclasses of A (B and C). Then you could risk that listA
contains non-B objects. When you then try to take objects out of listB
you could risk to get non-B objects out (e.g. an A or a C). That breaks the contract of the listB
variable declaration.
listA = listB;
If you could make this assignment, it would be possible to insert A and C instances into the List pointed to by listB
. You could do that via the listA
reference, which is declared to be of List. Thus you could insert non-B objects into a list declared to hold B (or B subclass) instances.
The purpose
When creating reusable methods that operate on collections of a specific type.
You should use List <? extends A>
(upper bound) if you are going to read .get() from the list
When you know that the instances in the collection are of instances of A or subclasses of A, it is safe to read the instances of the collection and cast them to A instances.
You can not insert elements into the list, because you don\'t know if the list is typed to the class A, B or C.
You should use List <? super A>
(lower bound) if you are going to insert .add() into the list
When you know that the list is typed to either A, or a superclass of A, it is safe to insert instances of A or subclasses of A (e.g. B or C) into the list.
You cannot read from the list though, except if it casts the read objects to Object. The elements already present in the list could be of any type that is either an A or superclass of A, but it is not possible to know exactly which class it is.
Please read more here - http://tutorials.jenkov.com/java-generics/wildcards.html
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)