When doing some not really fancy things with Java, I came over an error with generics that I was not able to understand why it doesn't work. The code is:
package test;
import java.util.*;
public class TestClass {
public static class A extends C{}
public static class B extends C{}
public static class C{}
public static class D<T>{}
public static class E<T>{}
public static void main(String args[]){
E<D<? extends C>> a = new E<D<A>>();
E<D<? extends Object>> b = new E<D<? extends C>>();
E<D<? extends A>> c = new E<D<A>>();
E<D<? super A>> d = new E<D<A>>();
D<? extends C> e = new D<A>();
D<? extends A> f = new D<A>();
D<? extends A> g = new D<A>();
}
}
The error I get when compiling is:
test/TestClass.java:11: incompatible types found : test.TestClass.E<test.TestClass.D<test.TestClass.A>> required: test.TestClass.E<test.TestClass.D<? extends test.TestClass.C>> E<D<? extends C>> a = new E<D<A>>(); ^ test/TestClass.java:12: incompatible types found : test.TestClass.E<test.TestClass.D<? extends test.TestClass.C>> required: test.TestClass.E<test.TestClass.D<? extends java.lang.Object>> E<D<? extends Object>> b = new E<D<? extends C>>(); ^ test/TestClass.java:13: incompatible types found : test.TestClass.E<test.TestClass.D<test.TestClass.A>> required: test.TestClass.E<test.TestClass.D<? extends test.TestClass.A>> E<D<? extends A>> c = new E<D<A>>(); ^ test/TestClass.java:14: incompatible types found : test.TestClass.E<test.TestClass.D<test.TestClass.A>> required: test.TestClass.E<test.TestClass.D<? super test.TestClass.A>> E<D<? super A>> d = new E<D<A>>(); ^ 4 errors
If E<D<? extends C>>
is found, that should surely match E<D<? extends Object>>
, right? Or have I missed something?
Maybe this would help you understand:
ArrayList<Object> aList = new ArrayList<String>();
This doesn't compile either with a similar error.
EDIT: Consult with: http://www.ibm.com/developerworks/java/library/j-jtp01255.html
This is basically the same case as posted previous. Basically, in a generics case, you are never allowed to do this assigment:
Think of this example:
ArrayList<Object> alist = new ArrayList<Number>();
This doesn't compile because it is not type safe. You could possibly add Strings aList. You are trying to assign a list of objects that are guaranteed to be Numbers but can be any Number, to a list that only guarantees you to contain objects but that can be any objects. If the compiler allowed this case it would loosen the restriction on which types of objects are allowed to get into the list. This is why you must use the wildcard ?, as such:
ArrayList<? extends Object> alist = new ArrayList<Number>();
To the compiler ArrayList<? extends Object>
, means "an ArrayList of some specific type '?' that I don't know, but which I know extends Object. This ArrayList is guaranteed to contain only elements of this unknown '?' type, and therefore contains only objects". In this case the compiler will however not allow you to do alist.add(2). Why is that the case, because the compiler doesn't know the type of the elements of the list, and can't guarantee that you are allowed to insert Integer objects into it.
You are right in thinking that D<? extends Object>
is a supertype of D<? extends C>
. However, List<D<? extends Object>>
is not a subtype of List<D<? extends C>>
, you should be using List<? extends D<? extends C>>
.
Your case is basically equivalent to
ArrayList<D<? extends Object>> alist = new ArrayList<D<? extends C>>();
You have the same problem as above, the list on the right hand side can only contain object of class D whose type Parameter is C, and you are trying to assign it to a list (on the left hand side) can contain objects of class D whose type parameter can be any object.
So if the compiler allowed your code would not be type safe, and the following would fail.
ArrayList<D<? extends Object>> alist = new ArrayList<D<? extends C>>(); //< not type safe
alist.add(new D<Number>); //< oops
In short, what you need for your specific example is the following:
// type parameter of left hand side is ? extends subtype
List<? extends D<? extends Object>> b = Arrays.asList(new D<A>(), new D<B>());
// type parameter of left hand side is identical
List<D<? extends C>> b = Arrays.asList(new D<A>(), new D<B>());
// type parameter of left hand side is ? extends subtype
List<? extends D<? extends C>> c = Arrays.asList(new D<A>());
// type parameter of left hand side is identical
List<D<A>> c = Arrays.asList(new D<A>());
Hope this helps.
Check the type of the object returned by Arrays.asList call. I would guess it returns a List<D<? extends C>> object, which will not be castable to a List<D<? extends Object>>.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With