How to iterate over a mixed list using foreach? - java

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.

Related

How to assign List<? extends BaseClass> to List<BaseClass>

having
class BaseClass implements IData ();
class ChildClassA() extends BaseClass;
class ChildClassB() extends BaseClass;
since cannot do
List<BaseClass> aList = new ArrayList<ChildClassA>()
so there is a
List<? extends IData> aList
for pointint to either
ArrayList<ChildClassA>(),
or
ArrayList<ChildClassB>()
the aList is built by other routing at runtime, and that part of code has a function to take a List<IData> from the the aList
the question is if the List<? extends IData> aList is point to ArrayList<ChildClassA>() or ArrayList<ChildClassB>(),
can it do ListData<IData> outputList = (List<IData>) aList? something like below:
(seems it is working, but not sure if there is better way to assign the generics array other than casting.)
Edit: the output of the List<IData> outputList is for read only use (immutable), no insert/delete on it, it will only iterate the IData to react on what the IData really is.
List<? extends IData> aList = new ArrayList<ChildClassA>();
ListData<IData> outputList = (List<IData>)aList
List<? extends IData> aList = new ArrayList<ChildClassB>();
ListData<IData> outputList = (List<IData>)aList
tl;dr Use Collections#unmodifiableList:
List<IData> outputList = Collections.unmodifiableList(aList);
For more information on this topic, you might want to get familiar with the PECS principle.
It's not possible, because the two types are incompatible.
A List<BaseClass> is just what it is declared, a list of BaseClass objects. More precisely, it makes two guarantees:
objects retrieved from it are assignable to BaseClass
every object that is assignable to BaseClass can be added to it (and no other)
A List<? extends BaseClass> is a more loose declaration. Precisely, it simply does not make the second guarantee. However, not only the guarantee is gone, but it is now impossible to add items to it, since the exact generic type of the list is undefined. It might even change for the same list declaration (not the same list object) at runtime.
As a consequence, a List<? extends BaseClass> is not assignable to a List<BaseClass>, since the latter makes a guarantee the first is unable to fulfill.
Practically speaking, consider the following method:
public List<BaseClass> makeList() {
// TODO implement method
return null;
}
If someone implements this method, returning a List<? extends BaseClass>, a client using this method would be unable to add items to it, although its declaration indicates otherwise.
Because of that, such an assignment results in a compilation error.
To fix the example problem the loose declaration can be added to the method:
public List<? extends BaseClass> makeList() {
// TODO implement method
return null;
}
This will signal every client, that the list returned from this method is not meant for adding items to it.
Now let's get back to your use case. In my opinion the most appropriate fix is to the rephrase the function that
take[s] a List from the the aList.
As it seems it is currently declared as
public void useList(List<BaseClass> list);
but since it does not add items to the list, it should be declared as
public void useList(List<? extends BaseClass> list);
However, if that method is part of a currently unchangeable API, you can still do:
List<? extends BaseClass> list;
....
List<BaseClass> tmp = Collections.unmodifiableList(list);
useList(tmp);
No, it is unsafe.
After that cast it would be legit to add to the list that is supposed to contain only ChildClassA typed elements, element of the other child type ChildClassB type and vice-versa.
We can simply your code a bit to make it more obvious why this should not be allowed:
List<ChildClassA> aList = new ArrayList<ChildClassA>();
aList.add(a1);
aList.add(a2);
//...
List<IData> iDataList = (List<IData>) aList;
iDataList.add(b1);
iDataList.add(b2);
//...
for (ChildClassA a : aList) {
// a some point a is going to be assigned b1 or b2 and they results in cast
// exception.
}
Note that iDataList makes reference to the very same list object as aList.
If that cast was allowed then you would be able to add elements to aList that are not ChildClassA instances.
The best solution is on the details.
If the problem is that a third-party library requires a List<IData> typed reference and as long as it is only for reading you can use a unmodifiable proxy as returned by Collections.unmodifiableList:
import java.util.Collections;
//...
final List<ChildClassA> aList = new ArrayList<>();
//... add stuff to aList
final List<IData> readOnlyIDataList = Collections.unmodifiableList(aList);
//... read only access operations readOnlyIDataList

Is List<Double> a subtype of List<? extends Number> and why?

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);

Difference for <? super/extends String> in method and variable declaration

Given:
import java.util.*;
public class Hancock {
//insert code here
list.add("foo");
}
}
Which two code fragments, inserted independently at line 5, will compile without warnings? (Choose two)
A. public void addString(List list) {
B. public void addString(List<String> list) {
C. public void addString(List<? super String> list) {
D. public void addString(List<? extends String> list) {
Correct answers are B & C.
Answers A and B are quite clear for me. For the answers C & D i know which way the inheritence is going, however i cannot understand why answer D does not compile in Eclipse while all others do (A with warrning about generic, B & C without warrings).
Error in Eclipse for answer D is The method add(capture#1-of ? extends String) in the type List<capture#1-of ? extends String> is not applicable for the arguments (String).
On the other hand this compiles:
public void addString() {
List<? extends String> list1 = new ArrayList<String>();
List<? super String> list2 = new ArrayList<String>();
}
Why? Why <? super String> does not compile in method declaration while it does compile in variable declaration.
I know that String is final class and cannot be extended by any other class but that does not explain to me what is going on here.
First, let's see answer C:
public void addString(List<? super String> list) {
list.add("foo");
}
This method declaration says that you will be allowed to pass List objects which are parametrized by some super class of String, for example String or Object. So:
If you pass List<String> the list.add("foo") will be perfectly valid.
If you pass List<Object> the list.add("foo") will be perfectly valid, because "foo" is a String (and you can add a String to a List<Object>).
This means that answer C is correct.
Lets now see answer D.
If you have a method declaration like this:
public void addString(List<? extends String> list) {
}
this means that you will be able to pass List objects parametrized by some unknown subtype of String. So, when you do list.add("foo"); the compiler won't be aware if the provided object has a type that matches the unknown subtype of String and therefore raises a compile-time error.
When you have:
public void addString() {
List<? extends String> list1 = new ArrayList<String>();
List<? super String> list2 = new ArrayList<String>();
}
This fragment compiles fine, because list1 is defined to hold List objects that are of some unknown subtype of String, including the String itself, which is why it's valid.
The problem is that you won't be able to add anything, except null.
As for list2, the variable can hold List objects which are parametrized by some super-type of String, including the String itself.
More info:
What is PESC?
What is the difference between super and extends in Java wildcards?
Firstly, generics don't care that String is final. They work the same way for final and non-final classes.
With that in mind, it should be apparent why D is not allowed - if it was, you could do this:
void test() {
List<Integer> integers = new ArrayList<Integer>();
addADouble(integers);
int a = integers.get(0); // ????
}
void addADouble(List<? extends Number> list) {
list.add(new Double(5.0));
}
List<? extends Number> is a "List of something that extends Number, but you don't know exactly what it's a List of." - it might be a List<Double>, or a List<Integer>, or a List<Number>, or a List<YourCustomSubclassOfNumber>, so you can't add anything to it because you don't know if it's the right type.

Java Generics: How does method inference work when wildcard is being used in the method parameters?

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 */

What is a difference between <? super E> and <? extends E>?

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
}

Categories

Resources