I’ve a collection type:
Collection<A> collecA
And I’ve a list in my object:
List<B> listB
Where B is extending A
class B extends A { ... }
But I can’t do the following:
collecA = listB
I can’t understand why since Collection is implemented by List.
Advertisement
Answer
Let’s assume for a moment you could do what you describe:
class B extends A { ... }
Collection<A> collecA;
List<B> listB;
collecA = listB; // normally an error, but lets pretend its allowed
collecA.add(new A()); // PROBLEM!
The method call collecA.add(new A()) appears okay since collecA is a collection
that holds As. However, if the above assignment were allowed, then we have a
problem becausecollecA is really reference to a List<B> instance – I just
added an A into a list that can only hold Bs!
Asker also said:
I can’t understand why since Collection is implemented by List.
It doesn’t matter that Collection is a superclass of List. This assignment is illegal even if you used two lists.
class B extends A { ... }
List<A> listA;
List<B> listB;
listA = listB; // still an error, still leads to the same problem
The key is that the List<A> variable can reference only Lists that can hold As. However, a List<B> instance cannot hold As. Therefore, a List<A> variable like listA cannot be assigned a reference to a List<B> instance referred to bylistB.
Or more generally speaking: B being a subclass of A does not imply that SomeGenericClass<B> is a subclass of SomeGenericClass<A> (JLS §4.10: Subtyping does not extend through generic types: T <: U does not imply that C<T> <: C<U>.)
It was this example/analogy from the Java Generics Tutorial that helped me understand this:
http://java.sun.com/docs/books/tutorial/java/generics/subtyping.html
“Understanding why becomes much easier if you think of tangible objects — things you can actually picture — such as a cage:
// A cage is a collection of things, with bars to keep them in. interface Cage<E> extends Collection<E>; ... Cage<Lion> lionCage = ...; Cage<Butterfly> butterflyCage = ...;
But what about an “animal cage”? English is ambiguous, so to be precise let’s assume we’re talking about an “all-animal cage”:
Cage<Animal> animalCage = ...;
This is a cage designed to hold all kinds of animals, mixed together. It must have bars strong enough to hold in the lions, and spaced closely enough to hold in the butterflies.
…
Since a lion is a kind of animal (Lion is a subtype of Animal), the question then becomes, “Is a lion cage a kind of animal cage? Is Cage<Lion> a subtype of Cage<Animal>?”. By the above definition of animal cage, the answer must be “no”. This is surprising! But it makes perfect sense when you think about it: A lion cage cannot be assumed to keep in butterflies, and a butterfly cage cannot be assumed to hold in lions. Therefore, neither cage can be considered an “all-animal” cage:
animalCage = lionCage; // compile-time error animalCage = butterflyCage; // compile-time error
“