Ответ 1
Предположим на мгновение вы могли бы сделать то, что вы описали:
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!
Вызов метода collecA.add(new A())
выглядит нормально, так как collecA
представляет собой набор
которая содержит A
s. Однако, если указанное присвоение было разрешено, то мы имеем
потому что collecA
действительно ссылается на экземпляр List<B>
- я просто
добавлен A
в список, который может содержать только B
s!
Аскер также сказал:
Я не понимаю, почему, поскольку Collection реализуется List.
Не имеет значения, что Collection является суперклассом List. Это назначение является незаконным, даже если вы использовали два списка.
class B extends A { ... }
List<A> listA;
List<B> listB;
listA = listB; // still an error, still leads to the same problem
Ключ состоит в том, что переменная List<A>
может ссылаться только на List
, которая может содержать A
s. Однако экземпляр List<B>
не может содержать A
s. Поэтому переменной List<A>
, подобной listA
, не может быть присвоена ссылка на экземпляр List<B>
, на который ссылается listB
.
Или, вообще говоря, B
, являющийся подклассом A
, имеет не, что SomeGenericClass<B>
является подклассом SomeGenericClass<A>
(JLS §4.10: подтипирование не распространяется на общие типы: T <: U
не означает, что C<T> <: C<U>
.)
Именно этот пример/аналогия из учебника Java Generics помог мне понять это:
http://java.sun.com/docs/books/tutorial/java/generics/subtyping.html
"Понимание того, почему становится намного проще, если вы думаете о материальных объектах - вещи, которые вы можете реально изобразить, например, клетка:
// 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 = ...;
Но как насчет "клетки животных"? Английский двусмыслен, поэтому, если быть точным, предположим, что мы говорим о клетке "all-animal cage" :
Cage<Animal> animalCage = ...;
Это клетка, предназначенная для хранения всех видов животных, смешанных. У него должны быть решетки, достаточно сильные, чтобы держаться у львов, и располагаться достаточно близко, чтобы удержать бабочек.
...
Поскольку лев - это своего рода животное (Лев - подтип животного), тогда возникает вопрос: "Является ли клетка льва своего рода клеткой для животных?" Cage<Lion>
подтип Cage<Animal>
? ". Согласно приведенному выше определению клетки для животных, ответ должен быть" нет ". Это удивительно! Но это имеет смысл, когда вы думаете об этом: клетку-лев нельзя считать бабочкой, и клетку бабочки нельзя считать удерживающей во львах. Поэтому ни клетка не может считаться клеткой" все животные":
animalCage = lionCage; // compile-time error
animalCage = butterflyCage; // compile-time error
"