<? extends C> specifies upper bounds of the type, which means the type has to be extended from C. <? extends Object> is apparently more general, thus it's incompatible.

Think about this use case. By specifying an upper bound, you expect certain minimum interface to be implemented. Say you have a doIt() method declared in C. Any class extending C would have that method but not every class extending Object (That's every class in Java).

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>>.

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.

When assigning to a variable (E<T>) with a non-wildcard generic type T, the object being assigned must have exactly T as its generic type (including all generic type parameters of T, wildcard and non-wildcard). In your case T is D<A>, which is not the same type as D<? extends C>.

What you can do, because D<A> is assignable to D<? extends C>, is use the wildcard type: E<? extends D<? extends C>> a = new E<D<A>();

Basically, you're declaring the b as something that can accept general contents (D<anything>), but the list you're assigning to it is something that only accepts more specific contents (D<nearest common superclass of A and B>).

Declaring b as List<D<? extends Object>> implies that you could, say, b.add(new D<String>()), but it's actually a List<D<? extends C>>, so you can't.

You cannot inherit in the generics-parameter. Say you have following references:

List<Object> a;
List<String> b;

Now you assign both the same list: a = b;

If some code does the following:

a.add(new Integer(1));

What happens if someone does the following:

String s = b.get(0);

You would get an Integer of a List of Strings. That should not work. That's why List and List are incompatible, although an String can be assigned to an Object-reference. Generics don't work with inheritance.

The thing is that List<D<? extends Object>> basically defines a new class and so does List<D<? extends C>>. Even when c extends Object that doesn't mean that List<D<? extends C>> extends List<D<? extends Object>> and that would be needed for the assigment to work.

Althoug this series of articles is written for the .NET platform the description of the problem still holds true for Java generics

The last line of the new main method is why a1 can't be set to a2. If the compiler let you do that, then you would be able to put a D<B> into a container that was declared to only hold D<A>s.

The reason this isn't obvious from your original example is because you didn't create a separate variable that referenced the object using the more restrictive E<D<A>> typing. But hopefully now you can see that if such a reference exists, its type safety would be compromised by the assignment you tried to do.

I beg to differ, Whether is list-of-something is the same as a list-of-something-else is about understanding inheritance, and substitutability. <br/> That, IMO, is about OO fundaments; therefore the reference to C++ should be acceptable
–
EveryoneAug 15 '09 at 2:26

The example still isn't correct (or even helping, IMO). The allAtSea.addAll() line doesn't compile, and neither does the allObjects.add().
–
JornAug 15 '09 at 10:10