The java HashSet implementation has a constructor:
public HashSet(Collection<? extends E> c) {
map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
Why it is Collection<? extends E> c? This isn't enough: Collection<E> c?
The concept here is called variance (covariance, contravariance).
Let's say you have the following two classes:
class A {}
class B extends A {}
In this case, you can say that an instance of B is an instance of A. In other words, the following code is perfectly valid:
A instance = new B();
Now, generic classes in Java are, by default, invariant. That means that a List<B> is not a List<A>. In other words, the following code will not compile:
List<A> as = new ArrayList<B>(); // error - Type mismatch!
However, if you have an instance of B, sure you can add it to a list of A (because B extends A):
List<A> as = new ArrayList<A>();
as.add(new B());
Now, let's say you have a method that deals with lists of A by consuming its instances:
void printAs(List<A> as) { ... }
It would be tempting to make the following call:
List<B> bs = new ArrayList<B>();
printAs(bs); // error!
However, it won't compile! If you want to make such a call work, you have to make sure that the argument, List<B>, is a subtype of the type expected by the method. This is done by using covariance:
void printAs2(List<? extends A> as) { ... }
List<B> bs = new ArrayList<B>();
printAs2(bs);
Now, this method takes an instance of List<? extends A>, and it is true that List<B> extends List<? extends A>, because B extends A. This is the concept of covariance.
After this introduction, we can go back to the constructor of HashSet you mention:
public HashSet(Collection<? extends E> c) { ... }
What this means is that the following code will work:
HashSet<B> bs = new HashSet<B>();
HashSet<A> as = new HashSet<A>(bs);
It works because HashSet<B> is a HashSet<? extends A>.
If the constructor were declared as HashSet(Collection<E> c), then the second line on the wouldn't compile, because, even if HashSet<E> extends Collection<E>, it is not true that HashSet<B> extends HashSet<A> (invariace).
This is because when HashMap can contain and object that inherits from E, so you want to be able to pass a collection of objects of any type that inherits E, not just E.
If it were Collection, then you wouldn't be able to pass an ArrayList<F>, where F extends E, for example.
Related
If a class B extends class A, one cannot cast List<A> to List<B> (cast 1 below). This makes sense, because if it were allowed, then one could read a B from the list even if it contained none.
However, in the code below, cast 2 from List<? extends A> to List<B> causes a warning. Shouldn't it generate an error for the same reason as before? In the code, the list only contains one object that is an A but not a B, and yet it is in a list deemed List<B>.
package test;
import java.util.LinkedList;
import java.util.List;
public class TypeLowerBoundCasting {
static class A {}
static class B extends A {}
static void method1() {
List<A> listOfAs = new LinkedList<A>();
listOfAs.add(new A());
// List<B> listOfAsAsListOfBs = (List<B>) listOfAs ; // cast 1: compiler error
// B b = listOfAsAsListOfBs.get(0); // that would be bad
}
static void method2() {
LinkedList<A> listOfAs = new LinkedList<A>();
listOfAs.add(new A());
List<? extends A> listOfAExtensions = listOfAs;
List<B> listOfAsAsListOfBs = (List<B>) listOfAExtensions; // cast 2: warning, but compiles
B b = listOfAsAsListOfBs.get(0); // that IS bad; causes a run-time error.
}
public static void main(String[] args) {
method2();
}
}
A List<? extends A> might be a List<B>, so you can cast:
List<? extends A> list = new ArrayList<B>(); // lose type information
List<B> result = (List<B>) list; // regain type information
Similar to how you can do:
Object o = "Hello World!"; // lose type information
String s = (String) o; // regain type information
Unfortunately, the first cast is unchecked. But a cast in that place is still a valid option, as you can see.
But a List<A> can never actually be a List<B> (unless you abuse raw types), because List<A> is not assignable from a List<B> (i.e. List<B> does not 'extend' List<A>) so you can't cast:
List<A> list = new ArrayList<B>(); // Only works with: (List<A>) (List) new ArrayList<B>();
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
Suppose we're dealing with the following set up:
A extends B
Main does:
public void doIt() {
List<A> listOfA = new ArrayList<A>();
listOfA.add(new A());
listOfA.add(new A());
C c = new C();
// We know that really, listOfA is going to be modified
// in some way and will be returned to us, thus, it is
// ok to cast result back to what we know it to be
List<A> a = (List<A>) c.doSomethingWithListOfA(listOfA);
}
When C has a method
public List<? extends B> doSomethingWithListOfA(List<? extends B>
listOfObjectsThatExtendB) {
return someFormofListA;
}
The cast of (List) c.doSomethingWithListOfA(listOfA); comes back with - Type safety: Unchecked cast from List<capture#1-of ? extends B> to List<A> warning.
I wonder is it possibly because some other class may also extend B thus making compiler unsure whether in fact is it a list of A or possibly X that extends B?
Other then suppressing the warning, how can one check for this? (unchecked cast)
It's not type-safe because that method could return a list of any type which is a subtype of B -- which may or may no be A.
How about writing this:
public <T extends B> List<T> doSomethingWithListOfA(List<T> listOfObjectsThatExtendB) {
return listOfObjectsThatExtendB;
}
and now casting is no longer needed:
List<A> a = c.doSomethingWithListOfA(listOfA);
Can you please explain why it is possible to do:
import java.util.ArrayList;
import java.util.List;
public class Covariance {
class A {
}
class B extends A {
}
class C extends A {
}
public void testSmth() throws Exception {
List<? extends A> la = new ArrayList<A>();
A a = la.get(0);
// la.add(new B()); - doesn't compile
List<? super B> lb = new ArrayList<A>();
// lb.add(new A()); - doesn't compile
lb.add(new B());
Object object = lb.get(0);
}
}
I don't understand, why it is not possible to add something to covariant list la, but it's still possible to add B to contravariant list lb - but not A to lb.
From my point of view, it should be possible to add everything extending A to List. I can see the only reason of not doing that because it is easy to add C to list of B, like
List<B> lst = new ArrayList<B>();
List<? extends A> lstB = lst;
lstB.add(C); // this is valid for <? extends B> but list lst would contain instance of B.
Probably the same is true for contravariance, e.g
List<B> lst = new ArrayList<B>;
List<? super C> lstC = lst;
lstC.add(new C());
Object obj = lstC.get(0);
What I don't understand - why it is not possible to do
B b = lstC.get(0);
It is obvious that on this stage super of C would be class B - Java doesn't allow multiple inheritance.
Also why it prohibits
lstC.add(new B());
it's not clear for me.
To understand what's going on with the super keyword, consider the following:
import java.util.ArrayList;
import java.util.List;
public class Covariance {
class A {
}
class B extends A {
}
class C extends A {
}
class D extends C {}
public void testSmth() throws Exception {
List<? super D> ld = new ArrayList<C>();
}
}
Hopefully this illustrates that ld can be a List of any super type of D, even one that be a subclass of A.
consider
List<? extends A> la = new ArrayList<C>();
it's a list of C. if we could add B to it, that would violate the list type.
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