Как бросить список наследования объектов к набору объектов в Java?

У меня есть тип набора:

Collection<A> collecA

И у меня есть список в моем объекте:

List<B> listB

Где B расширяет A

class B extends A { ... }

Но я не могу сделать следующего:

collecA = listB

Я не могу понять, почему, так как Набор реализован Списком.

11
задан Michael Petrotta 2 May 2010 в 20:00
поделиться

4 ответа

Предположим на мгновение, что вы можете сделать то, что описываете:

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 — коллекция который содержит As. Однако, если указанное выше присваивание было разрешено, то мы имеем проблема, потому что collecA действительно является ссылкой на экземпляр List — я просто добавил A в список, который может содержать только B!

Аскер также сказал:

Я не могу понять почему, так как Коллекция реализована Листом.

Неважно, что Collection является надклассом List. Это присвоение является недопустимым, даже если вы использовали два списка.

class B extends A { ... }
List<A> listA;
List<B> listB;
listA = listB;  // still an error, still leads to the same problem

Ключ в том, что переменная List может ссылаться только на List, которые могут содержать A. Однако экземпляр List не может содержать As.Следовательно, List переменная, такая как listA, не может быть назначена ссылкой на List экземпляр, на который ссылаетсясписокB.

Или, в более общем смысле: B, являющийся подклассом A, не означает, что SomeGenericClass является подклассом SomeGenericClass (JLS §4.10: Подтипирование не распространяется на универсальные типы: T <: U не означает, что C <: C.)


Этот пример/аналогия из Java Generics Tutorial помог мне понять это:

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 подтипом Клетка<Животное>?". По приведенному выше определению клетки для животных ответ должен быть «нет».Это удивительно! Но это имеет смысл, если задуматься: нельзя предположить, что клетка со львом может содержать бабочек, а клетка с бабочкой не может содержать львов. Следовательно, ни одна из клеток не может считаться клеткой для животных:

animalCage = lionCage;  // compile-time error
animalCage = butterflyCage; // compile-time error

"

16
ответ дан 3 December 2019 в 02:30
поделиться
Collection<? extends A> collecA

Это исправляет ситуацию. Проблема не в List extends Collection, а в общих типах.

10
ответ дан 3 December 2019 в 02:30
поделиться

Java generics не являются ковариантными.

См. Теория и практика Java: Generics Gotchas для более подробной информации.

На странице показан простой пример, который мог бы разрушить систему типов, если бы она была ковариантной:

Представьте, что вы можете присвоить List к List. Тогда следующий код позволит вам поместить в List что-то, что не является Integer:

List<Integer> li = new ArrayList<Integer>();
List<Number> ln = li; // illegal
ln.add(new Float(3.1415)); // ERROR: Adds a float to li, which is a list of Integers!
5
ответ дан 3 December 2019 в 02:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: