Предположим на мгновение, что вы можете сделать то, что описали:
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
с. Однако, если вышеупомянутое назначение было разрешено, то у нас есть
проблема, потому что 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
с. Однако экземпляр List<B>
не может содержать A
с. Следовательно, переменной List<A>
, такой как listA
, нельзя присвоить ссылку на List<B>
экземпляр , на который ссылается listB
.
Или, в более общем смысле: B
подкласс A
означает не , что SomeGenericClass<B>
является подклассом SomeGenericClass<A>
( JLS § 4.10 : Подтип не распространяется на универсальные типы: T <: U
не означает, что C<T> <: C<U>
. )
Именно этот пример / аналогия из Общего руководства по Java помог мне понять это:
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 = ...;
Но как насчет "клетки для животных"? Английский язык неоднозначен, поэтому, если быть точным, давайте предположим, что мы говорим о «клетке для животных» :
Cage<Animal> animalCage = ...;
Это клетка, предназначенная для содержания всех видов животных, , смешанных вместе . Он должен иметь достаточно прочные стержни, чтобы удерживать их во львах, и располагаться достаточно близко, чтобы удерживать бабочек.
...
Поскольку лев является своего рода животным (лев является подтипом животного), возникает вопрос: «Является ли клетка льва своего рода клеткой для животных? Является ли Cage<Lion>
подтипом Cage<Animal>
?». По приведенному выше определению клетки для животных ответ должен быть «нет». Это удивительно! Но это имеет смысл, когда вы думаете об этом: нельзя предположить, что в клетке для львов содержатся бабочки, а в клетке для бабочек нельзя содержать львов. Следовательно, ни одна клетка не может считаться клеткой для животных:
animalCage = lionCage; // compile-time error
animalCage = butterflyCage; // compile-time error
"