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.
<? super C>
would mean that your type is restricted to something above C
in the type hierarchy. (Sorry for the extremely late reply. I guess we didn't have comment notifications 2 years ago?) –
Calica If you have a class hierarchy A
, B
is a subclass of A
, and C
and D
are both subclasses 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.
List<? super B>
describes as List accepts the type that is parent class of class B? Which is why C and D won't compile hmm? –
Interphase 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));
}
}
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)learn by example:
consider the sort()
method in Collections
class which use both extends
and super
:
public static <T extends Comparable<? super T>> void sort(List<T> list){...}
so
why <T extends Comparable<...>>
: becuase we need list items (T
) to be a subclass of the Comparable
interface.
why Comparable<? super T>
: becuase we allow the Comparable
type
to be a Comparable of any super type of T.
Consider
interface Comparable<T>{
public int compareTo(T o);
}
public static <T extends Comparable<? super T>> void sort(List<T> list){...}
public static <T extends Comparable<T>> void sort2(List<T> list){...}
class A implements Comparable<A>{
@Override
public int compareTo(A o) {
...
}
}
class B extends A {
}
List<A> listA = new ArrayList<>();
List<B> listB = new ArrayList<>();
sort(listA); //ok
sort(listB); //ok
sort2(listA); //ok
sort2(listB); //Error
© 2022 - 2024 — McMap. All rights reserved.