Spec-Zone .ru
спецификации, руководства, описания, API
|
Как описано в Обобщениях, Наследование, и Подтипы, универсальные классы или интерфейсы не связываются просто, потому что есть отношение между их типами. Однако, можно использовать подстановочные знаки, чтобы создать отношение между универсальными классами или интерфейсами.
Учитывая следующие два регулярных (неуниверсальных) класса:
class A { /* ... */ } class B extends A { /* ... */ }
Было бы разумно записать следующий код:
B b = new B(); A a = b;
Этот пример показывает, что наследование регулярных классов следует за этим правилом выделения подтипов: B class является подтипом class A, если B расширяет A. Это правило не применяется к универсальным типам:
List<B> lb = new ArrayList<>(); List<A> la = lb; // compile-time error
Учитывая, что Integer является подтипом Number, каково отношение между List<Integer> и List<Number>?
Хотя Integer является подтипом Number, List<Integer> не является подтипом List<Number> и, фактически, эти два типа не связываются. Общим родителем List<Number> и List<Integer> является List<?>.
Чтобы создать отношение между этими классами так, чтобы код мог получить доступ к методам Number через элементы List<Integer>, используйте верхний ограниченный подстановочный знак:
List<? extends Integer> intList = new ArrayList<>(); List<? extends Number> numList = intList; // OK. List<? extends Integer> is a subtype of List<? extends Number>
Поскольку Integer является подтипом Number, и numList является списком объектов Number, отношение теперь существует между intList (список объектов Integer) и numList. Следующая схема показывает отношения между несколькими классами List, объявленными и с верхними и с более низкими ограниченными подстановочными знаками.
У Направляющих линий для Подстановочного раздела Использования есть больше информации о разветвлениях использования верхних и более низких ограниченных подстановочных знаков.