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 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.
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:
If this method only reads objects from List<A>, then we should be allowed to give List<A-sub> to this method. (Because A-sub IS a A)
If this method only inserts objects to 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
Related
I have a Storage class:
class Storage<E> {
void add(E e) {
// add element
};
void addAll(Iterable<? extends E> src) {
for (E e : src)
add(e);
}
}
There are two classes where class Child extends Parent:
Parent
class Parent implements Comparable<Parent> {
#Override
public int compareTo(Parent o) {
return 0; // some comparison logic
}
}
Child
class Child extends Parent {
}
Driver class:
import java.util.Arrays;
import java.util.List;
public class GenericTest {
public static void main(String[] args) {
/******** CASE 1 *********/
Storage<Parent> ds = new Storage<Parent>();
ds.add(new Parent());
ds.addAll(Arrays.asList(new Parent()));
// Type params are invariant.
// But List<Child> is possible due to bounded wildcard type on addAll
ds.addAll(Arrays.asList(new Child())); // Makes sense
/******** CASE 2 *********/
List<Child> t = Arrays.asList();
max(t);
}
static <T extends Comparable<T>> T max(List<T> list) {
return null; // Return null so code can compile
}
}
Because Storage is a generic class, the operations on its method makes sense; I get how case 1 is working.
In case 2, with above signature of max in GenericTest, I get the compilation error:
The method max(List<T>) in the type GenericTest is not applicable for the arguments (List<Child>)
I understand that Comparable<Child> is not a sub-type of Comparable<Parent> (Typed params are invariant).
So, I updated signature to
// update Comparable<T> to Comparable<? super T>
static <T extends Comparable<? super T>> T max(List<T> list)
Now, the code compiles and inferred signature is
<Child> Child GenericTest.max(List<Child> list)
This makes sense.
When I update the signature to
// update List<T> to List<? extends T>
static <T extends Comparable<T>> T max(List<? extends T> list)
the code compiles and inferred signature is
<Parent> Parent GenericTest.max(List<? extends Parent> list)
I couldn't understand how updating List<T> to List<? extends T> made the compiler infer the type Parent.
I mean, for a generic method (on which there is direct invocation using type Child), how did ? extends T helped compiler refer the parent class of Child? Note that this signature has Comparable<T> (and not Comparable<? super T).
Isn't extends about a type which is T itself and its sub-classes?
Edit:
Java 8 comes with updated type-inference rules.
The below is sufficient for type-inference in Java 8 and later, but not for Java 7 and below:
static <T extends Comparable<T>> T max(List<? extends T> list)
It gives compilation error:
Bound mismatch: The generic method max(List<? extends T>) of type GenericTest is not applicable for the arguments (List<Child>). The inferred type Child is not a valid substitute for the bounded parameter <T extends Comparable<T>>
The signaure
static <T extends Comparable<? super T>> void max(List<T> list)
is sufficient for Java 7, though.
To make things clearer, the class Child:
extends Parent
implements Comparable<Parent>
1) static <T extends Comparable<T>> T max(List<T> list)
T is Child
fails because Child is not a Comparable<Child>
2) static <T extends Comparable<? super T>> T max(List<T> list)
T is Child
? is Parent
it works because Child implements Comparable<Parent super Child>
3) static <T extends Comparable<T>> T max(List<? extends T> list)
T is Parent
? is Child
it works because Child extends Parent implements Comparable<Parent>
Here in case 3), finding a valid T class can be seen as: "find the first super class of Child that implements a Comparable of itself".
As in case 1), it cannot be Child because it is not a Comparable<Child>.
The first (and only) super class of Child that implements Comparable of itself is Parent.
I couldn't understand how updating List<T> to List<? extends T> made the compiler infer the type Parent.
List<T> forces T to be Child
List<? extends T> forces ? to be Child, not T
To me it fails with both JDK 8 and JDK 7, so I don't see the inconsistency which you describe between those JDks
JDK 8 compilation
JDK 7 compilation
As to why it fails it is called PECS (Producer Extends Consumer Super)
The following answer has helped me a lot to understand it.
If you say <? extends SomeType>, then you wanna describe a ‘box’ that
is the same size or smaller than the ‘SomeType’ box.
Taking in consideration the aforementioned, when you described max method as
static <T extends Comparable<T>> T max(List<? extends T> list)
With your declaration List<? extends T> list you need a container of the same or smaller than T. Which could be Child as you use it.
List<Child> t = Arrays.asList();
so this should have compiled.
However the return type is of <T extends Comparable<T>> T which then is translated into Child extends Comparable<Child>.
Java however has a limitation that prevents you from implementing the same generic interface (in your case Comparable) with different type parameters.
That is why the error says
required: java.util.List<? extends T>
found: java.util.List<Child> reason: inferred type does not
conform to declared bound(s)
inferred: Child
bound(s): java.lang.Comparable<Child>
Solution
You should have declared the return type with <T extends Comparable<? super T>>
Contra-variance: ? super T ( the family of all types that are
supertypes of T) - a wildcard with a lower bound. T is the lower-most
class in the inheritance hierarchy.
from a previous answer on PECS
In that case it would have compiled as it would have set the bound to Comparable<Parent>.
This question already has answers here:
Difference between <? super T> and <? extends T> in Java [duplicate]
(14 answers)
Closed 2 years ago.
I have the code below. It seems that I can't put an object of class Nonlife that is a superclass of class Vehicle into a container of type Collection<? super Vehicle> ALTHOUGH there is a keyword "super" in the wildcard type, and only objects of class Vehicle and SUV that is a subclass of class Vehicle are feasible. Could someone give me some advice?
public class SUV extends Vehicle
public class Vehicle extends Nonlife implements Externalizable
public class Nonlife extends Thing
public class Thing implements Comparable<Thing>, Serializable
public class SupperWildcardTest20200830 {
public static void main(String[] args) {
Collection<Thing> coll = new ArrayList<>();
appendVehicle2Collection(coll);
appendSuv2Collection(coll);
for (Thing el: coll) {
System.out.println("" + el);
}
}
public static void appendVehicle2Collection(Collection<? super Vehicle> coll) {
coll.add(new Vehicle());
}
public static void appendSuv2Collection(Collection<? super Vehicle> coll) {
coll.add(new SUV());
}
public static void appendNolife2Collection(Collection<? super Vehicle> coll) {
/**
* incompatible types: Nonlife cannot be converted to CAP#1
* where CAP#1 is a fresh type-variable:
* CAP#1 extends Object super: Vehicle from capture of ? super Vehicle
*/
coll.add(new Nonlife());
}
}
The only thing you know for sure about Collection<? super Vehicle> is that it is a collection of Vehicles, or a collection of a supertype of Vehicles. So the only thing you know for sure that you can put into this collection are Vehicles. So you are allowed to pass a Collection of NonLifes to the method, but you may still only put Vehicles or subtypes into the collection within the method.
In general: with super, you can put values of the mentioned type in it, or subtypes. With extends you can retrieve the mentioned type from the collection, or retrieve them as a supertype.
This is a Wildcard Capture problem.
TL;DR - when you use a wildcard (be it with super or extends) in the Generic Collection type definition, getting element from that collection and casting it appropriately can be considered safe, while adding element into the collection is not, and this mechanism is implemented for the safety purpose.
Let's examine the example given in the Oracle Documentation, which demonstrates the reason of why this safety is needed (this example uses extends but same principle applies for super):
The code:
import java.util.List;
public class WildcardErrorBad {
void swapFirst(List<? extends Number> l1, List<? extends Number> l2) {
Number temp = l1.get(0);
l1.set(0, l2.get(0)); // expected a CAP#1 extends Number, got a CAP#2 extends Number;
l2.set(0, temp); // expected a CAP#1 extends Number, got a Number
}
}
does not compile, as it is attempting an unsafe operation, because, if you will invoke this method as follows:
List<Integer> li = Arrays.asList(1, 2, 3);
List<Double> ld = Arrays.asList(10.10, 20.20, 30.30);
swapFirst(li, ld);
while List<Integer> and List<Double> both fulfill the criteria of List<? extends Number>, it is clearly incorrect to take an item from a list of Integer values and attempt to place it into a list of Double values.
Another example I liked is given by Jon Skeet, and it looks like this.
You might also want to read this.
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 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.
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:
If this method only reads objects from List<A>, then we should be allowed to give List<A-sub> to this method. (Because A-sub IS a A)
If this method only inserts objects to 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
In Java, the Collections class contains the following method:
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> c)
Its signature is well-known for its advanced use of generics,
so much that it is mentioned in the Java in a Nutshell book
and in the official Sun Generics Tutorial.
However, I could not find a convincing answer to the following question:
Why is the formal parameter of type Collection<? extends T>, rather
than Collection<T>? What's the added benefit?
Type inference is a tricky topic that I'll admit that I don't know that much about. However, examine this example:
public class ScratchPad {
private static class A implements Comparable<A> {
public int compareTo(A o) { return 0; }
}
private static class B extends A {}
private static class C extends B {}
public static void main(String[] args)
{
Collection<C> coll = null;
B b = Scratchpad.<B>min(coll);
}
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> c) {
return null;
}
//public static <T extends Object & Comparable<? super T>> T min(Collection<T> c) {
// return null;
//}
}
Consider that the first signature of min() allows the call to compile whereas the second does not. This isn't a very practical example, since one must ask why I would be explicitly typing the method to <B>, but perhaps there is an implicit inference where B would be the inferred type.
One benefit of the ? is that it prohibits additions of items to the Collection
I think it actually doesn't give you anything more for this method, however its a good habit to get into when T is part of the class and not just a static method.
They are including it here so it can become the new convention where every generic should be extended by ?
A class of T should follow PECS: What is PECS (Producer Extends Consumer Super)?
But a static method doesn't need to (at least the parameters, the return value should always)
This is to support a legacy signature of the method in Java 1.4 ( and before ).
Prior to Java 5 the signature for these methods was
public static Object min ( Collection c );
With multiple bounds the erasure rules make the first bound the raw type of the method, so without Object & the signature would be
public static Comparable min ( Collection c );
and legacy code would break.
This is taken from O'Reilly's Java Generics and Collections book, chapter 3.6
Building on the comments I put on Mark's answer, if you have something like
class Play {
class A implements Comparable<A> {
#Override
public int compareTo(A o) {
return 0;
}
}
class B extends A {
}
class C extends A {
}
public static <T extends Object & Comparable<? super T>> T min(
Collection<? extends T> c) {
Iterator<? extends T> i = c.iterator();
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) < 0)
candidate = next;
}
return candidate;
}
public static List<? extends A> getMixedList() {
Play p = new Play();
ArrayList<A> c = new ArrayList<A>();
c.add(p.new C());
c.add(p.new B());
return c;
}
public static void main(String[] args) {
ArrayList<A> c = new ArrayList<A>();
Collection<? extends A> coll = getMixedList();
A a = Play.min(coll);
}
}
It's clearer that min returns an object of type A (the actual signature is <A> A Play.min(Collection<? extends A> c) ). If you leave min(Collection<T>) without the extends part then Play.min(coll) will have the following signature <? extends A> ? extends A Play.min(Collection<? extends A> c) which isn't as clear.
Here is the case, I have two classes A, B, and a generic interface C
Class A implements Comparable<A> {...}
interface C<T> {...}
//this class is not longer generic type, I do not know if this matter.
Class B extends A implements C<A> {...}
Then, at other class, I got a B List and sort it as follow
List<B> list = new ArrayList<B>();
Collections.sort(list);
This works perfectly, but now I would like to change the list of B to the generic interface C, so that it can be more general.
List<C<A>> list = new ArrayList<C<A>>();
Collections.sort(list);
This time I got the Error as follow:
Bound mismatch: The generic method sort(List<T>) of type Collections is not
applicable for the arguments (List<C<A>>). The inferred type C<A> is not a
valid substitute for the bounded parameter <T extends Comparable<? super T>>
I have tried the following modifications (of course does not work):
change C to interface C<T> extends Comparable<T>{...}
change B to class B extends A implements C<A>, Comparable<T> {...}
Can anybody help me?
change C to interface C extends Comparable{...}
Class B extends A implements C {...}
As you would have already seen from the error messages, these two won't work together as there will be a conflict in B's definition w.r.t to Comparable<A> and Comparable<C<A>>.
Since A is already implementing Comparable<A>, you can achieve the following
List<C<A>> list = new ArrayList<C<A>>();
Collections.sort(list);
by defining a Comparator for C<A> as follows:
class CTComparator<T> implements Comparator<C<T>>
{
#Override
public int compare(C<T> o1, C<T> o2)
{
return 0;
}
}
and then applying the sort method with this comparator:
List<C<T>> list = new ArrayList<C<T>>();
Collections.sort(list, comparator);
Since C<A> is not having the visibility of the Comparator defined in A hence it's complaining. Define a new comparator of C<A> as blow, it should be fine then.
List<C<A>> list = new ArrayList<C<A>>();
Collections.sort(list, new Comparator<C<A>>() {
#Override
public int compare(C<A> o1, C<A> o2) {
//implement the comarison
return 0;
}
});
If you expect C<T> to be generically comparable based on the type it contains, you should make it comparable on itself (C<T>, not T), but bound its value type to those that implement Comparable. Something like this:
public class C<T extends Comparable<? super T>> extends Comparable<C<T>> {
private final T value;
#Override
public int compareTo(C<T> that) {
return this.value.compareTo(that.value);
}
}
This only makes sense for some containers, such as those that simply wrap a value.