What is the difference between <? super E> and <? extends E>?
For instance when you take a look at class java.util.concurrent.LinkedBlockingQueue there is the following signature for the constructor:
public LinkedBlockingQueue(Collection<? extends E> c)
and for one for the method:
public int drainTo(Collection<? super E> c)
The first (<? super E>) says that it's "some type which is an ancestor (superclass) of E"; the second (<? extends E>) says that it's "some type which is a subclass of E". (In both cases E itself is okay.)
So the constructor uses the ? extends E form so it guarantees that when it fetches values from the collection, they will all be E or some subclass (i.e. it's compatible). The drainTo method is trying to put values into the collection, so the collection has to have an element type of E or a superclass.
As an example, suppose you have a class hierarchy like this:
Parent extends Object
Child extends Parent
and a LinkedBlockingQueue<Parent>. You can construct this passing in a List<Child> which will copy all the elements safely, because every Child is a parent. You couldn't pass in a List<Object> because some elements might not be compatible with Parent.
Likewise you can drain that queue into a List<Object> because every Parent is an Object... but you couldn't drain it into a List<Child> because the List<Child> expects all its elements to be compatible with Child.
The reasons for this are based on how Java implements generics.
An Arrays Example
With arrays you can do this (arrays are covariant)
Integer[] myInts = {1,2,3,4};
Number[] myNumber = myInts;
But, what would happen if you try to do this?
myNumber[0] = 3.14; //attempt of heap pollution
This last line would compile just fine, but if you run this code, you could get an ArrayStoreException. Because you’re trying to put a double into an integer array (regardless of being accessed through a number reference).
This means that you can fool the compiler, but you cannot fool the runtime type system. And this is so because arrays are what we call reifiable types. This means that at runtime Java knows that this array was actually instantiated as an array of integers which simply happens to be accessed through a reference of type Number[].
So, as you can see, one thing is the actual type of the object, and another thing is the type of the reference that you use to access it, right?
The Problem with Java Generics
Now, the problem with Java generic types is that the type information is discarded by the compiler and it is not available at run time. This process is called type erasure. There are good reason for implementing generics like this in Java, but that's a long story, and it has to do, among other things, with binary compatibility with pre-existing code (see How we got the generics we have).
But the important point here is that since, at runtime there is no type information, there is no way to ensure that we are not committing heap pollution.
For instance,
List<Integer> myInts = new ArrayList<Integer>();
myInts.add(1);
myInts.add(2);
List<Number> myNums = myInts; //compiler error
myNums.add(3.14); //heap pollution
If the Java compiler does not stop you from doing this, the runtime type system cannot stop you either, because there is no way, at runtime, to determine that this list was supposed to be a list of integers only. The Java runtime would let you put whatever you want into this list, when it should only contain integers, because when it was created, it was declared as a list of integers.
As such, the designers of Java made sure that you cannot fool the compiler. If you cannot fool the compiler (as we can do with arrays) you cannot fool the runtime type system either.
As such, we say that generic types are non-reifiable.
Evidently, this would hamper polymorphism. Consider the following example:
static long sum(Number[] numbers) {
long summation = 0;
for(Number number : numbers) {
summation += number.longValue();
}
return summation;
}
Now you could use it like this:
Integer[] myInts = {1,2,3,4,5};
Long[] myLongs = {1L, 2L, 3L, 4L, 5L};
Double[] myDoubles = {1.0, 2.0, 3.0, 4.0, 5.0};
System.out.println(sum(myInts));
System.out.println(sum(myLongs));
System.out.println(sum(myDoubles));
But if you attempt to implement the same code with generic collections, you will not succeed:
static long sum(List<Number> numbers) {
long summation = 0;
for(Number number : numbers) {
summation += number.longValue();
}
return summation;
}
You would get compiler erros if you try to...
List<Integer> myInts = asList(1,2,3,4,5);
List<Long> myLongs = asList(1L, 2L, 3L, 4L, 5L);
List<Double> myDoubles = asList(1.0, 2.0, 3.0, 4.0, 5.0);
System.out.println(sum(myInts)); //compiler error
System.out.println(sum(myLongs)); //compiler error
System.out.println(sum(myDoubles)); //compiler error
The solution is to learn to use two powerful features of Java generics known as covariance and contravariance.
Covariance
With covariance you can read items from a structure, but you cannot write anything into it. All these are valid declarations.
List<? extends Number> myNums = new ArrayList<Integer>();
List<? extends Number> myNums = new ArrayList<Float>();
List<? extends Number> myNums = new ArrayList<Double>();
And you can read from myNums:
Number n = myNums.get(0);
Because you can be sure that whatever the actual list contains, it can be upcasted to a Number (after all anything that extends Number is a Number, right?)
However, you are not allowed to put anything into a covariant structure.
myNumst.add(45L); //compiler error
This would not be allowed, because Java cannot guarantee what is the actual type of the object in the generic structure. It can be anything that extends Number, but the compiler cannot be sure. So you can read, but not write.
Contravariance
With contravariance you can do the opposite. You can put things into a generic structure, but you cannot read out from it.
List<Object> myObjs = new List<Object>();
myObjs.add("Luke");
myObjs.add("Obi-wan");
List<? super Number> myNums = myObjs;
myNums.add(10);
myNums.add(3.14);
In this case, the actual nature of the object is a List of Objects, and through contravariance, you can put Numbers into it, basically because all numbers have Object as their common ancestor. As such, all Numbers are objects, and therefore this is valid.
However, you cannot safely read anything from this contravariant structure assuming that you will get a number.
Number myNum = myNums.get(0); //compiler-error
As you can see, if the compiler allowed you to write this line, you would get a ClassCastException at runtime (because item 0 in the list is an Object, not a Number).
Get/Put Principle
As such, use covariance when you only intend to take generic values out of a structure, use contravariance when you only intend to put generic values into a structure, and use the exact generic type when you intend to do both.
The best example I have is the following which copies any kind of numbers from one list into another list. It only gets items from the source, and it only puts items in the target.
public static void copy(List<? extends Number> source, List<? super Number> target) {
for(Number number : source) {
target.add(number);
}
}
Thanks to the powers of covariance and contravariance this works for a case like this:
List<Integer> myInts = asList(1,2,3,4);
List<Double> myDoubles = asList(3.14, 6.28);
List<Object> myObjs = new ArrayList<Object>();
copy(myInts, myObjs);
copy(myDoubles, myObjs);
<? extends E> defines E as the upper bound: "This can be cast to E".
<? super E> defines E as the lower bound: "E can be cast to this."
<? super E> means any object including E that is parent of E
<? extends E> means any object including E that is child of E .
I'm going to try and answer this. But to get a really good answer you should check Joshua Bloch's book Effective Java (2nd Edition). He describes the mnemonic PECS, which stands for "Producer Extends, Consumer Super".
The idea is that if you code is consuming the generic values from the object then you should use extends. but if you are producing new values for the generic type you should use super.
So for example:
public void pushAll(Iterable<? extends E> src) {
for (E e: src)
push(e);
}
And
public void popAll(Collection<? super E> dst) {
while (!isEmpty())
dst.add(pop())
}
But really you should check out this book:
http://java.sun.com/docs/books/effective/
You might want to google for the terms contravariance (<? super E>) and covariance (<? extends E>). I found that the most useful thing when comprehending generics was for me to understand the method signature of Collection.addAll:
public interface Collection<T> {
public boolean addAll(Collection<? extends T> c);
}
Just as you'd want to be able to add a String to a List<Object>:
List<Object> lo = ...
lo.add("Hello")
You should also be able to add a List<String> (or any collection of Strings) via the addAll method:
List<String> ls = ...
lo.addAll(ls)
However you should realize that a List<Object> and a List<String> are not equivalent and nor is the latter a subclass of the former. What is needed is the concept of a covariant type parameter - i.e. the <? extends T> bit.
Once you have this, it's simple to think of scenarios where you want contravariance also (check the Comparable interface).
Before the answer; Please be clear that
Generics only compile time feature to ensure TYPE_SAFETY, it wont b available during RUNTIME.
Only a reference with Generics will force the type safety; if the reference don't declared with generics then it will work without type safty.
Example:
List stringList = new ArrayList<String>();
stringList.add(new Integer(10)); // will be successful.
Hope this will help you to understand wildcard more clear.
//NOTE CE - Compilation Error
// 4 - For
class A {}
class B extends A {}
public class Test {
public static void main(String args[]) {
A aObj = new A();
B bObj = new B();
//We can add object of same type (A) or its subType is legal
List<A> list_A = new ArrayList<A>();
list_A.add(aObj);
list_A.add(bObj); // A aObj = new B(); //Valid
//list_A.add(new String()); Compilation error (CE);
//can't add other type A aObj != new String();
//We can add object of same type (B) or its subType is legal
List<B> list_B = new ArrayList<B>();
//list_B.add(aObj); CE; can't add super type obj to subclass reference
//Above is wrong similar like B bObj = new A(); which is wrong
list_B.add(bObj);
//Wild card (?) must only come for the reference (left side)
//Both the below are wrong;
//List<? super A> wildCard_Wrongly_Used = new ArrayList<? super A>();
//List<? extends A> wildCard_Wrongly_Used = new ArrayList<? extends A>();
//Both <? extends A>; and <? super A> reference will accept = new ArrayList<A>
List<? super A> list_4__A_AND_SuperClass_A = new ArrayList<A>();
list_4__A_AND_SuperClass_A = new ArrayList<Object>();
//list_4_A_AND_SuperClass_A = new ArrayList<B>(); CE B is SubClass of A
//list_4_A_AND_SuperClass_A = new ArrayList<String>(); CE String is not super of A
List<? extends A> list_4__A_AND_SubClass_A = new ArrayList<A>();
list_4__A_AND_SubClass_A = new ArrayList<B>();
//list_4__A_AND_SubClass_A = new ArrayList<Object>(); CE Object is SuperClass of A
//CE; super reference, only accepts list of A or its super classes.
//List<? super A> list_4__A_AND_SuperClass_A = new ArrayList<String>();
//CE; extends reference, only accepts list of A or its sub classes.
//List<? extends A> list_4__A_AND_SubClass_A = new ArrayList<Object>();
//With super keyword we can use the same reference to add objects
//Any sub class object can be assigned to super class reference (A)
list_4__A_AND_SuperClass_A.add(aObj);
list_4__A_AND_SuperClass_A.add(bObj); // A aObj = new B();
//list_4__A_AND_SuperClass_A.add(new Object()); // A aObj != new Object();
//list_4__A_AND_SuperClass_A.add(new String()); CE can't add other type
//We can't put anything into "? extends" structure.
//list_4__A_AND_SubClass_A.add(aObj); compilation error
//list_4__A_AND_SubClass_A.add(bObj); compilation error
//list_4__A_AND_SubClass_A.add(""); compilation error
//The Reason is below
//List<Apple> apples = new ArrayList<Apple>();
//List<? extends Fruit> fruits = apples;
//fruits.add(new Strawberry()); THIS IS WORNG :)
//Use the ? extends wildcard if you need to retrieve object from a data structure.
//Use the ? super wildcard if you need to put objects in a data structure.
//If you need to do both things, don't use any wildcard.
//Another Solution
//We need a strong reference(without wild card) to add objects
list_A = (ArrayList<A>) list_4__A_AND_SubClass_A;
list_A.add(aObj);
list_A.add(bObj);
list_B = (List<B>) list_4__A_AND_SubClass_A;
//list_B.add(aObj); compilation error
list_B.add(bObj);
private Map<Class<? extends Animal>, List<? extends Animal>> animalListMap;
public void registerAnimal(Class<? extends Animal> animalClass, Animal animalObject) {
if (animalListMap.containsKey(animalClass)) {
//Append to the existing List
/* The ? extends Animal is a wildcard bounded by the Animal class. So animalListMap.get(animalObject);
could return a List<Donkey>, List<Mouse>, List<Pikachu>, assuming Donkey, Mouse, and Pikachu were all sub classes of Animal.
However, with the wildcard, you are telling the compiler that you don't care what the actual type is as long as it is a sub type of Animal.
*/
//List<? extends Animal> animalList = animalListMap.get(animalObject);
//animalList.add(animalObject); //Compilation Error because of List<? extends Animal>
List<Animal> animalList = animalListMap.get(animalClass);
animalList.add(animalObject);
}
}
}
}
A wildcard with an upper bound looks like " ? extends Type " and stands for the family of all types that are subtypes of Type , type Type being included. Type is called the upper bound .
A wildcard with a lower bound looks like " ? super Type " and stands for the family of all types that are supertypes of Type , type Type being included. Type is called the lower bound .
You have a Parent class and a Child class inherited from Parent class.The Parent Class is inherited from another class called GrandParent Class.So Order of inheritence is GrandParent > Parent > Child.
Now,
< ? extends Parent > - This accepts Parent class or either Child class
< ? super Parent > - This accepts Parent class or either GrandParent class
super: List<? super T> 'super' guarantees object to be ADDED to the collection is of type T.
extends: List<? extends T> 'extend' guarantees object READ from collection is of type T.
Explanation:
There are three things that need to be considered while understanding a difference between 'super' and 'extends' from type safety point of view.
1.Assigning : What type of collection can be assigned to the generic reference.
2.Adding : What type can be added to the collection referred.
3.Reading : What type can be read from collection referred
'<? super T>' ensures-
Any collection of type T or its superclass can be assigned.
Any object of type T or its subclass can be added to collection, as it
will always pass a 'Is A' test for T.
Type of the item read from the collection can not be guarantied except from being of type 'Object'. It can be anything of type T or its superclass which includes type 'Object'.
'<? extends T>' ensures-
Any collection of type T or its subclass can be assigned.
No object can be added as we can not determine type of reference.
(Even object of type 'T' can not be added, because generic reference might be assigned to the collection of subtype of 'T')
Item read from the collection can be guarantied to be of type 'T'.
Consider class hierarchy
class Base {}
class Intermediate extends Base{}
class ThirdLayer extends Intermediate{}
public void testGenerics() {
/**
* super: List<? super T> super guarantees object to be ADDED to the collection
* if of type T.
*
* extends: List<? extends T> extend guarantees object READ from collection is
* of type T
*
* Super:-
*
* Assigning : You can assign collection of Type T or its super classes
* including 'Object' class.
*
* Adding: You can add objects of anything of Type T or of its subclasses, as we
* are sure that the object of type T of its subclass always passes Is A test
* for T. You can NOT add any object of superclass of T.
*
* Reading: Always returns Object
*/
/**
* To a Collection of superclass of Intermediate we can assign Collection of
* element of intermediate or its Parent Class including Object class.
*/
List<? super Intermediate> lst = new ArrayList<Base>();
lst = new ArrayList<Intermediate>();
lst = new ArrayList<Object>();
//Can not assign Collection of subtype
lst = new ArrayList<ThirdLayer>(); //Error!
/**
* Elements of subtype of 'Intemediate' can be added as assigned collection is
* guaranteed to be of type 'Intermediate
*/
lst.add(new ThirdLayer());
lst.add(new Intermediate());
// Can not add any object of superclass of Intermediate
lst.add(new Base()); //Error!
Object o = lst.get(0);
// Element fetched from collection can not inferred to be of type anything
// but 'Object'.
Intermediate thr = lst.get(0); //Error!
/**
* extends: List<? extends T> extend guarantees object read from collection is
* of type T
* Assigning : You can assign collection of Type T or its subclasses.
*
* Adding: You cannot add objects of anything of Type T or even objects of its
* subclasses. This is because we can not be sure about the type of collection
* assigned to the reference.
*
* Reading: Always returns object of type 'T'
*/
// Can assign collection of class Intermediate or its subclasses.
List<? extends Intermediate> lst1 = new ArrayList<ThirdLayer>();
lst1 = new ArrayList<Base>(); //Error! can not assign super class collection
/**
* No element can be added to the collection as we can not be sure of
* type of the collection. It can be collection of Class 'Intermediate'
* or collection of its subtype. For example if a reference happens to be
* holding a list of class ThirdLayer, it should not be allowed to add an
* element of type Intermediate. Hence no addition is allowed including type
* 'Intermediate'.
*/
lst1.add(new Base()); //Error!
lst1.add(new ThirdLayer()); //Error!
lst1.add(new Intermediate()); //Error!
/**
* Return type is always guaranteed to be of type 'Intermediate'. Even if the
* collection hold by the reference is of subtype like 'ThirdLayer', it always
* passes the 'IS A' test for 'Intermediate'
*/
Intermediate elm = lst1.get(0);
/**
* If you want a Collection to accept (aka to be allowed to add) elements of
* type T or its subclasses; simply declare a reference of type T i.e. List<T>
* myList;
*/
List<Intermediate> lst3 = new ArrayList<Intermediate>();
lst3 = new ArrayList<ThirdLayer>(); //Error!
lst3 = new ArrayList<Base>(); //Error!
lst3.add(new Intermediate());
lst3.add(new ThirdLayer()); // Allowed as ThirdLayer passes 'IS A' for Intermediate
lst3.add(new Base()); //Error! No guarantee for superclasses of Intermediate
}
Related
Here is what I know:
Double is a subtype of Number and List<Double> is not a subtype of List<Number>.
List<Dog> is not a subtype of List<Animal> because you can add Cat to List<Animal> but you can't do that with List<Dog>.
List<? extends Number> means this list can store variables of type Number and variables of subtype of Number. List<Double> means this list can store variables of type Double.
Please correct me if anything above is wrong and then Is List<Double> a subtype of List<? extends Number> and why?
All your items are correct.
Double is a subtype of Number and List<Double> is not a subtype of List<Number>.
List<Dog> is not a subtype of List<Animal> because you can add Cat to List<Animal> but you can't do that with List<Dog>.
That's correct. Generics aren't covariant (but arrays are!). Here's some follow up reading: Why are arrays covariant but generics are invariant?
List<? extends Number> means this list can store variables of type Number and variables of subtype of Number. List<Double> means this list can store variables of type Double.
This is true, but there's an important difference between List<Number> and List<? extends Number>. You can think of List<? extends Number> as a list of a specific Number-subtype (that is one of List<Double>, List<Integer>, List<Long>, ...) and a List<Number> as a list that can potentially contain a mix of Double, Integer, ...
As for your final question:
Is List<Double> a subtype of List<? extends Number>...
Yes, you can have for instance
List<Double> doubles = new ArrayList<>();
List<? extends Number> numbers = doubles;
... and why?
This is just the way subtyping is defined.
As for the motivation, suppose you have a method that accepts a list of numbers. If you let the parameter have the type List<Number> you won't be able to pass a List<Double> to it. (Your second item in your question explains why!) Instead, you can let the parameter have type List<? extends Number>. Since List<Double> is a subtype of List<? extends Number> it will work out.
There are a few points that should also be added
At runtime List<Double>, List<? extends Number>, List<?> and List<Object> are all identical. The generic parameter is not compiled at all. All the magic with generics is all compile time fun. This also means that if you have a List that is empty you have no idea what the generic parameter is!
Try not to think of the generic parameter as a "Subtype", the generic parameter really means "the class uses a generic parameter" so in this case "the list uses a Number". A good example of this is the HashMap source, if you have a look into the inner workings of it, it is actually storing an array of Entry, and the entries all have keys and values stored on them. When you look at more complex uses of generics you occasionally see this sort of use.
In the situation of a List the generic parameter means that the list stores that type of object, it could be that the object never stores an object of the type of the generic parameter at all! Like this:
public class DummyIterator<O> implements Iterator<O>{
public boolean hasNext() {
return false;
}
public O next() {
return null;
}
}
What does List<? extends Number> actually mean? Well it is pretty much the same as List<Number> for most uses. Keep in mind though that by saying ? you are pretty much saying 'I don't care about the type' which shows itself in this situation:
List<Double> doubles = new ArrayList<Double>();
List<? extends Number> numbers = doubles;
numbers.add(new Double(1)); //COMPILE ERROR
Number num = numbers.get(0);
So we can't add a Double to a <? extends Number>. But for this example:
List<Double> doubles = new ArrayList<Double>();
List<Number> numbers = doubles; //COMPILE ERROR
numbers.add(new Integer(1));
Number num = numbers.get(0);
You can't assign the List<Double> to a List<Number> which makes sense as you are specifically telling it, that lists use only Number types
So where should you use a ?? well really anywhere you could say "I don't care about the generic parameter" so for instance:
boolean equalListSizes(List<?> list1, List<?> list2) {
return list1.size() == list2.size();
}
You would use the ? extends Number type of format only where you are not modifying the object using the generic parameter. so for instance:
Number firstItem(List<? extends Number> list1) {
return list1.get(0);
}
Instead of using the ? and ? extends Number formats try using generics on the class / method instead, in most cases it makes your code more readable as well!:
<T extends Number> T firstItem(List<T> list1) {
return list1.get(0);
}
Class:
class Animal{}
class Dog extends Animal{}
class AnimalHouse<A extends Animal> {
List<A> animalsInside = new ArrayList<A>();
void enterHouse(A animal){
animalsInside.add(A);
}
A leaveHouse() {
return animalsInside.remove(0);
}
}
AnimalHouse<Dog> ah = new AnimalHouse<Dog>();
ah.enterHouse(new Dog());
Dog rufus = ah.leaveHouse();
As a bonus thought around generics you can also parameterise methods to return a particular class. A good example of this is the any() method in junit and the empty list collection:
Dog rufus = Matchers.<Dog>any();
List<Dog> dogs = Collections.<Dog>emptyList();
This syntax allows you to specify the return type of an object. Sometimes quite useful to know (makes some casting redundant)!
At runtime, List<T> and List<U> are identical to List (1).
However, this will change with the introduction of value types(expected to make it in the JDK 9 or JDK 10 release, not sooner than mid 2016). List<T> will not be the same as List<U> anymore due to numerous constraints explained here by Brian Goetz: http://cr.openjdk.java.net/~briangoetz/valhalla/specialization.html
(1) - T and U types are different in the previous statements
It helped me to see generics as constraints or contracts, not as types with subtypes.
So a variable List<? extends Number> var says: var is a list of some unknown type ?, which is constrained to be a subtype of Number.
List<Number> listN;
List<Double> listD;
List<? extends Number> listX;
...
Number n1 = ...;
Double d1 = ...;
...
listN.add(n1); // OK n1 is a Number
listN.add(d1); // OK d1 is a Double, which is a Number
listD.add(n1); // compile error, n1 is not a Double
listD.add(d1); // OK
listX.add(n1); // compile error, because the exact type of list is not known! (prevents putting a Dog in a Cat list)
listX.add(d1); // compile error, same cause
So when you can't even put a Number into a List<? extends Number>, whats the purpose of such a list? It allows you to work with lists of which the exact type does not matter for the task at hand:
// instead of several exactly typed methods...
int count(List<Number> numberList) {...}
int count(List<Object> objectList) {...}
// ...etc. you can have one with a degree of freedom:
int count(List<?> anyList) {...} // don't need to know the exact type of list
// instead of this...
Number sum(List<Number> numberList) {...}
Number sum(List<Double> doubleList) {...}
Number sum(List<Integer> integerList){...}
// you can do this, with a little less freedom in the ?
Number sum(List<? extends Number> list) {
// the only thing we need to know about the list's type is that it is some number type
...
Number ni = list.get(i);
...
}
Using wildcards ? extends X allows to relax rigid contracts to weaker conditions.
Using a named type parameter, you can establish constraints on allowed types between several variables:
// works for any type T of list, whatever T is
// T is the same in the argument and in the return
<T> T pickObject(List<T> list, int index) {
return list.get(index);
}
// works for any type T of list, if T is a Number type
// T is the same in the argument and in the return
<T extends Number> T pickNumber(List<T> list, int index) {
return list.get(index);
}
...
List<Number> list;
Number n = pickNumber(list);
There is a method :
public static <T> void addandDisp(Collection<T> cs, T t)
which is being called in the following way :
List<? extends Object> ls2 = new LinkedList<Number>();
addandDisp(ls2,new Object());
This gives a compile time error. On the other hand, if we had only one parameter, then the call is successful. Why is that ?
Moreover, this is successful :
List<? super String> ls1 = new LinkedList<String>();
addandDisp(ls1,new String());
while this is not :
List<? super String> ls1 = new LinkedList<Object>();
addandDisp(ls1,new Object());
What is the underlying logic ?
I would assume that addandDisp means add and display.
When you have a collection, defined as:
List<? extends Object> ls2 = new LinkedList<Number>();
This means that the compiler will allow you to assign the colletion to all the possible unknown subtypes of Object. Since you have the operation add, the compiler denies to give you green light, because it doesn't know if the provided object's type meets the restriction to be of the unknown subtype of Object. This is called covariance.
Similary, when you have a definition like this:
List<? super String> ls1 = new LinkedList<String>();
The compiler allows you to assing ls1 to:
LinkedList<String>(); //you can add Strings to the list
LinkedList<Object>(); //you can add Strings and Objects to the list
In this case, the compiler will be completely aware if the object you're trying to pass meets the condition to be subtype of the generic type of the collection. This is called contravariance.
More info:
What is PECS?
Here is another approach, but others gave a quite detailed response.
The first example:
List<? extends Object> ls0 = new LinkedList<Number>();
addandDisp(ls0, new Object());
Here ls0 may be of any type that is a subclass of Object, like a Number as your example shows.
Now what if this could work? It would mean that if you can put an Object into any of the collections.
Imagine I want to iterate your previous list of Number objects:
for (Number n : numbers) {
...
}
If I could put an Object here, then Plaff! I would get a class cast exception immediately.
The second example
List<? super String> ls1 = ...;
addandDisp(ls1,new String());
Let's play a bit with the object hierarchy: String is a subclass of CharSequence which is a subclass of Object.
You get ls1 here which is an unknown supertype of String (e.g., a CharSequence). Is it all right to put a String into a list of character sequences? Yup, it's okay, since they share the same interface for sure! You can handle them through it in the same way.
The third example
List<? super String> ls1 = ...;
addandDisp(ls1,new Object());
Let's suppose the previous situation: you assign ls1 a list of CharSequences. Can you add an object to a List<CharSequence>? Nope, for the same reason as the first example fails.
Hope that helps clarifying your issues a bit :-)
On the other hand, if we had only one parameter, then the call is successful. Why is that ?
Your method has a single type parameter. When you invoke a method, you either provide a type argument explicitly or have one be inferred implicitly.
When you invoke it like
addandDisp(ls2, new Object());
the compiler needs to extract a type to bind to T from both method arguments, since both method parameters rely on the method's type parameter, T.
The issue here is that ? extends Object and Object do not produce a single type that can be bound to T safely. Imagine you had
public static <T> void addandDisp(Collection<T> cs, T t) {
cs.add(t);
}
...
List<? extends Object> ls2 = new LinkedList<Number>();
addandDisp(ls2, new Object());
This add should not be allowed since an Object should not be used where a Number would have been expected. Type safety would break.
If you have a single parameter
public static <T> void addandDisp(Collection<T> cs) {
Then the compiler uses the single argument to infer the type argument. There is then no ambiguity about what to use.
1 example: Object is not ? extends Object (for example, Number is ? extends Object, but Object is not Number). Thus, it is not type safe.
2 example: String is ? super String. It is type safe.
3 example: Object is not ? super String. Not safe again.
The following code gives me an error for the line l.add
List<? extends Number> l = new ArrayList<Integer>();
l.add(1);
and forces me to write it as l.add(1, null);
Why is it so?
With a wildcard on the variable l, the compiler doesn't know (or care) which subclass of Number (or Number itself) the type parameter really is. It could be an ArrayList<Double> or an ArrayList<BigInteger>. It can't guarantee the type safety of what's passed in to add, and because of type erasure, the JVM can't catch a type mismatch either. So the compiler preserves type safety by disallowing such calls to add unless the value is null, which can be any type.
To get add to compile, you must declare l as:
List<? super Integer> l = new ArrayList<Integer>();
or you can remove the wildcard:
List<Integer> l = new ArrayList<Integer>();
It has to be:
List<? super Integer> l = new ArrayList<Integer>();
l.add(1);
Note the <? super Integer> declaration. It's called an upper-bound wildcard.
What does it do?
It restricts the Runtime type of the elements of the ArrayList to be one of the super classes of Integer, e.g. Integer, Number or Object, which means that you will be able to assign l to:
new ArrayList<Integer>
new ArrayList<Number>
new ArrayList<Object>
In the three cases, the statement l.add(1) is perfectly valid, so there's no compile-time error.
More info:
Upper-bounded wildcards in Java
What is PESC?
List<? extends Number> is different from List<T extends Number>. For List<T extends Number>, the l.add(new Integer(1)) would work.
If you use ? extends Number then you can't refer to the type, but you can still use ((List<Integer>)list).add((int) s).
You can write:
List<? extends Number> l = new ArrayList<>();
((List<Integer>)l).add((int) 1);
instead.
Generics is all about "Type Safety and invariance".
There are 2 scenario associated with your question.
Holding reference type.
Making modification to contents of that reference.
Your first statement is about holding the reference.
List<? extends Number> l = new ArrayList<Integer>();
Here, compiler ensures that l can hold the reference of Type List of objects which extends Number.
eg: List<Integer>, List<BigInteger>, List<Double> etc.
In our case it is List<Integer>. So far so good.
Now what am I allowed to add to l? Users could want to add anything (which extends Number, eg. Double, BigInteger or Integer). This would break the type safety. So to overcome this, the compiler ensures that the user is not allowed to add to such kind of references.
This kind of references are used mainly when we are only iterating through a type of list.
eg:
// Here numbers can take reference of List type of objects which extends Number.
public void printValue(List<? extends Number> numbers){
// Iterate through all the numbers.
for(Number number: numbers){
System.out.println(number.intValue());
}
}
Now coming to the 2nd scenario of this discussion, that is modifying the list.
For doing this, the compiler wants user to ensure type safety before making modification.
This can be done through <? super T>.
List<? super Number> n = new ArrayList<Number>();
Here the compiler allows to add subtypes of Number to n.
BigInteger b = new BigInteger("4");
Double d = new Double(2);
n.add(b); // valid
n.add(d); // valid
//Compiler won't allow here.
n.add(new CustomNumber()); // CustomNumber is not a subtype of Number. It addition in "n" is Invalid.
In simple words, List<? extends Number> declares a List of elements of unspecified type. You only specify that the type of the elements extends the class Number. l could be a List<Integer> or a List<Double>.
The compiler will allow to assign an element of the list to a Number, because it knows that anything in l is a Number or a subclass thereof.
But it will not allow to add any element to the list because the variable l could contain a List<Integer> that accepts only Integers, or a List<Double> that accepts only Doubles. No type is guaranteed to be accepted by the list. In some sense, List<? extends Number> is a read-only list.
If you need l to be a List of Numbers, maybe you pass it to a procedure that requires a List<Number>, then you must initialize it as an ArrayList<Number>().
But if you will always use Integers with that list, you should declare it as List<Integer> and initialize it with ArrayList<Integer>. Remember that Integer is a final class, it allows the compiler to optimize the code much more than with Numbers.
Supposedy i have the following:
class x {
public static void main(String [] args) {
List <?> a = new LinkedList<Object>();
List <? extends Object> b = new LinkedList<Object>();
List <? super Object> c = new LinkedList<Object>();
abc(a, "Hello"); // (1) Error
abc(b, "Hello"); // (2) Error
abc(c, "Hello"); // (3) ok
def(b); // (4) ok
// Showing inference at work
Integer[] a = {10, 20, 30}; // (5)
T is inferred to be ? extends Object
Method signature: ppp(? extends Object, ? extends Object[])
Method call signature: ppp(String, Integer[]);
ppp("Hello", a); // ok
}
static <T> void abc(List<T> a, T b) {}
static <T> void def(List<T> a) {}
static <T> void ppp(T t1, T[] t2){}
}
To begin with, look at clause 5 showing inference at work. Now clause 5 section is a working section.
If that is what it is, then why does clause (1) & (2) have errors?
From my view, all these 3 methods calling have the same inference generated since no actual type parameters is used on the abc method call.
method parameter <T> abc (List <T> a, T b>)
inferred <Object> abc (List <Object>, Object) // (4)
Please bear in mind, method abc() and def() is my method. Compiler doesn't know what i want to do with the List in this method. I might just print the list size or might not even do anything at all as shown above. So there is no get or set involved here.
CONTINUATION -->
This is getting very confusing for me.
class y {
public static void main(String [] args) {
List <Integer> a = new LinkedList<Integer>();
List <Object> b = new LinkedList<Object>();
ppp("Hello", new Integer(1)); // (20) ok
qqq("Hello", a); // (21) error
qqq("Hello", b); // (22) ok
}
static <T> void ppp(T t1, T t2) {}
static <T> void qqq(T t1, List <T> t2) {}
}
Note that clause 21 is the same as clause 20 except 2nd parameter is being made to be a List instead of Integer.
Clause 20 is ok cos' T is inferred to be Object.
Clause 22 is ok. Same reason as clause 20.
Clause 21 failed? T could also be inferred to be Object too - would work too?
The hard thing about the wildcard is to realize ? extends Foo does not mean "anything that extends Foo", but instead it means "some specific type that extends Foo". And since you are outside that definition, you have no way to know which specific sub-type of Foo it is.
Update:
As I said, it's complicated. Here are some comments on your code.
// a list of some specific type, and you don't know what type that is.
// it's a sub-type ob Object, yes, which means that you can do
// Object foo = a.get(0); , but the compiler has no way of knowing
// whether it's a String so you can't pass in a String
List <?> a = new LinkedList<Object>();
// same here. '?' and '? extends Object' are equivalent
List <? extends Object> b = new LinkedList<Object>();
// this is a list of Objects and superclasses thereof.
// since there are no superclasses of Object, this is equivalent to
// List<Object>. And through inheritance, a String is an Object, so
// you can pass it in.
List <? super Object> c = new LinkedList<Object>();
Update 2:
The problem here is that you are dealing with fixed, but unresolveable variables.
// you can pass in a List<String> and a String,
// but if you pass in a List<?>, the compiler has no idea what
// '?' is and just can't substitute 'String'.
// 'T' doesn't help you here, because 'T' can't match both
// '?' and 'String'.
static <T> void abc(List<T> a, T b) {}
// this works because 'T' substitutes '?' and doesn't have to worry
// about a 2nd parameter
static <T> void def(List<T> a) {}
Read this question, it might shed some light on the problem:
What is PECS (Producer Extends Consumer Super)?
You've set up a bit of a straw man by creating a LinkedList<Object> in each case. That can make it difficult to see the problem. What you have to remember is that when the compiler gets to those method invocations, it doesn't know that you created a LinkedList<Object>. It could be a LinkedList<Integer>, for example.
So let's look at your code with more interesting initializations:
List<Integer> integers = new LinkedList<Integer>();
List <?> a = integers;
List <? extends Object> b = integers;
List <? super Object> c = new LinkedList<Object>();
//INVALID. T maps to a type that could be Object OR anything else. "Hello"
//would only be type-assignable to T if T represented String, Object, CharSequence,
//Serializable, or Comparable
abc(a, "Hello");
//INVALID. T maps to a type that could be Object OR anything else. "Hello"
//would only be type-assignable to T if T represented String, Object, CharSequence,
//Serializable, or Comparable
abc(b, "Hello");
//VALID. T maps to an unknown super type of Object (which can only be Object itself)
//since String is already type-assignable to Object, it is of course guaranteed to be
//type-assignable to any of Object's super types.
abc(c, "Hello");
Integer i1 = integers.get(0);
Integer i2 = integers.get(1);
It doesn't take much to see that if the implementation of abc was this:
//a perfectly valid implementation
static <T> void abc(List<T> a, T b) {
a.add(b);
}
That you would get a ClassCastException when initializing i1.
From my view, all these 3 methods calling has the following inference generated since no actual type parameters is used on the abc static method call.
method parameter <T> abc (List <T> a, T b>)
inferred <Object> abc (List <Object>, Object) // (4)
This is categorically wrong. It is not inferred that T is Object in any of your examples, not even in the case of ? super Object. T is resolved to the capture of a, and unless you can assign a String to that capture (as is the case when it's ? super Object) you will have a type error.
Edit #1
Regarding your update (I've replaced your generic array with a List<T> since generic arrays needlessly cloud the issue):
// Showing inference at work
List<Integer> a = Arrays.asList(10, 20, 30); // (5)
T is inferred to be ? extends Object
Method signature: ppp(? extends Object, List<? extends Object>)
Method call signature: ppp(String, List<Integer>);
ppp("Hello", a); // ok
This is not correct. The crucial mistake you're making is here:
Method signature: ppp(? extends Object, List<? extends Object>)
This is not at all what the capture engine does or should translate your invocation into. It resolves T as <? extends Object> but as one specific capture of <? extends Object>. Let's call it capture-1-of<? extends Object>. Thus your method must be like this:
Method signature: ppp(capture-1-of<? extends Object>, List<capture-1-of<? extends Object>>)
This means that there is a binding between the two parameters...they must resolve to the same capture. In general it is very difficult to tell the compiler that two things are the same capture. In fact, even this is not a valid invocation of ppp (even though they are clearly the same capture):
List<? extends Integer> myList;
ppp(myList.get(0), myList);
One way we could invoke ppp is through a generic intermediary:
public static <T> void pppCaller(List<T> items) {
ppp(items.get(0), items);
}
pppCaller(myList);
The only sure-fire way you could invoke ppp with a wildcarded list would be to invoke it like this:
List<? extends Integer> myList = new ArrayList<Integer>();
ppp(null, myList);
That's because the null is the only thing that you can assign to anything. On the other hand, if you had this method:
private static <T> void qqq(T item1, T item2) {}
You could indeed invoke it like this:
List<? extends Integer> myList;
qqq(myList.get(0), myList.get(1));
Because in this case, the inference can generalize T to Object. Since List<? extends Integer> is not covariant with List<Object>, it cannot do the same for ppp().
However, what most people do to get around this is to relax their method signature. Instead, declare ppp as the following:
public static <T> ppp(T item, List<? super T> items) {
}
This follows the guidelines that Sean put in his post of "PECS"
If (your method) produces, use extends, if it consumes, use super.
Edit #2
Regarding your latest edit:
public static void main(String [] args) {
List <Integer> a = new LinkedList<Integer>();
qqq("Hello", a); // (21) error
}
static <T> void qqq(T t1, List <T> t2) {}
Object is not a valid inference for T. I think this is something fundamental you're missing, so I'll say it clear:
A List<Integer> is NOT type-assignable to List<Object>
Not at all. If it were, you could do something like this which obviously violates type safety:
List<Integer> myInts = new ArrayList<Integer>();
List<Object> myObjects = myInts; //doesn't compile!
myObjects.add("someString");
Integer firstInt = myInts.get(0); //ClassCastException!
So T cannot be inferred as Object, since it would require assigning a List<Integer> to a variable of type List<Object>.
A wildcard would then needed to induce subtype covariance
I'd rather say "try to simulate" since even after using wild-cards you can't get the same functionality you get for arrays.
Then the question is why clause (3) works and not clause(2) or (1)?
Consider the first declaration:
List <?> a = new LinkedList<Object>();
This declaration effectively says, I really don't know (or care) what kind of element the collection a contains. This effectively shuts you off from "mutating" the collection since you might end up adding elements of type which are not really compatible with a. You can have List<?> a = new ArrayList<String>() but you still won't be able to put anything in it. Basically, in case an add is allowed, the compiler can't guarantee the type safety of the collection.
List <? extends Object> b = new LinkedList<Object>();
Here you say b is a collection which contains elements which extend an Object. What kind of element, you don't know. This again as per the previous discussion doesn't allow you to add anything since you could end up compromising type safety.
List <? super Object> c = new LinkedList<Object>();
Here you say, c is a collection which contains elements of type Object and it's super-classes or in other words, at least an Object. Since each reference type in Java is assignment compatible with Object, it works in the third case.
Integer[] is a subtype of Object[], however List<Integer> is not a subtype of List<Object>. This is quite confusing; arrays are more primitive and should be avoided.
If a method parameter type is T[], it accepts all S[] where S is a subtype of T.
To do this with List, the type should be List<? extends T>. It accepts all List<S> where S is a subtype of T.
List<?> a means that a holds a specific type, which is unknown. Consider this more complete example:
List<Float> floats = new ArrayList<Float>();
List<?> a = floats; /* Alias "floats" as "a" */
abc(a, "Hello"); /* This won't compile... */
float f = floats.get(0); /* .. if it did, you'd get a ClassCastException */
static <T> abc(List<T> a, T b) {
a.add(b); /* Absolutely no problem here. */
}
List<? extends Object> means essentially the same thing as List<?>, and would cause the same error.
List<? super Object> means that the list holds a specific, but unknown super-type of Object, and the parameterized method can accept any object that is-a Object for the second parameter. While the method invocation is type-safe, attempting to assign an unsafe value to c will cause an error:
List<Number> numbers = new ArrayList<Number>();
List<? super Object> a = numbers; /* This won't compile... */
abc(a, "Hello");
Number n = numbers.get(0); /* ...if it did, you'd get a ClassCastException */
I'm wondering how to iterate over a List with mixed contents using foreach. See the example code below.
public class GenericsForeach {
class A {
void methodA() {
System.out.println(getClass().getSimpleName() + ": A");
}
}
class B extends A {
void methodB() {
System.out.println(getClass().getSimpleName() + ": B");
}
}
void test() {
List<A> listOfA = new ArrayList<A>();
listOfA.add(new A());
List<B> listOfB = new ArrayList<B>();
listOfB.add(new B());
List<? super A> mixed = new ArrayList<A>();
mixed.addAll(listOfA);
mixed.addAll(listOfB);
Iterator<? super A> it = mixed.iterator();
while (it.hasNext()) {
A item = (A) it.next();
item.methodA();
}
// XXX: this does not work
// for (A item : mixed) {
// item.methodA();
// }
}
public static void main(String[] args) {
new GenericsForeach().test();
}
}
I construct two lists with different, but related, content types A and B (B extends A). I add the two lists to a 'mixed' list, which I declare to contain <? super A> types. Since this mixed list is 'consuming' items of type A (or B) I applied Bloch's PECS rule (Producer Extends, Consumer Super) to determine that I need <? super A> here.
So far, so good. But now when I want to iterate over this mixed list, I can only seem to do it with an Iterator<? super A>, and a cast A item = (A) it.next(). When I try to use a foreach loop (see commented-out code), no joy:
Type mismatch: cannot convert from element type capture#8-of ? super GenericsForeach.A to GenericsForeach.A
Eclipse even helpfully offers to
Change type of 'item' to '? super A'
but this results in disaster:
for (? super A item : mixed) {
item.methodA();
}
So I don't know. Eclipse doesn't seem to know. Does anybody else here know if this is possible, and if it's not, why not?
You want just List<A> for mixed. My reasoning:
you want to be able to add items which are of type A, so it can't be List<? extends A> - that would include List<B>, which you can't add an A to.
you want to be able to guarantee that items which you fetch are of type A, so it can't be List<? super A> as that could be a List<Object> containing non-A elements.
So you end up with:
List<A> mixed = new ArrayList<A>();
mixed.addAll(listOfA);
mixed.addAll(listOfB);
for (A item : mixed) {
item.methodA();
}
Everyone here is correct. You want use List<A>.
But generics and assignments can be confusing, so a little more explanation is in order.
First, the problem you may have found is that you can't do this: List<A> = new List<B>(). The compiler won't let you assign a sub-type in to a super-type listing using generics. This is a little confusing, but it prevents problems with type mis-matches. (More detail can be found here: http://java.sun.com/docs/books/tutorial/java/generics/subtyping.html.) The correct terminology for this is List<? extends A> = new List<B>(). This tells the compiler that your assignment is legal.
At the same time, this syntax can confuse you to believing that <? extends A> means that all elements in this variable extend A. This isn't true - the syntax just a way to inform the compiler of legal assignments.
So, you want to use List<A> = new List<A> and then assign the elements to List<A> using addAll(). This is legal because the method addAll checks to make sure each element is valid before pushing it to the collection.