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 A
s. 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 B
s!
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 List
s that can hold A
s. However, a List<B>
instance cannot hold A
s. 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
“