Поскольку ListDataModel
только для чтения, его конструктор не может принимать только List<E>
.Можно обойтись без этой ошибки проектирования.
Более общий вопрос: предположим, что ListDataModel
доступен для записи, что теперь?
Если fooList
- это List<? extends Foo>
, то это, безусловно,List<W>
для бетона W
, который расширяется Foo
.Тогда мы должны иметь возможность new ListDataModel<W>(fooList)
, тип результата - DataModel<W>
, который можно назначить на DataModel<? extends Foo> model
.
Так компилятор внутренне рассуждает о подстановочных знаках (захват подстановочных знаков);Жаль, что мы не можем получить прямой доступ к W
в Java (это так называемый недетонируемый тип), но мы можем вызвать захват подстановочного знака посредством вызова метода:
static <W> ListDataModel<W> make(List<W> list)
{
return new ListDataModel<W>(list);
}
List<? extends Foo> fooList = ...;
DataModel<? extends Foo> model = make( fooList );
При компиляции make( fooList )
, компиляторвнутренне уточняет тип fooList
до List<W>
, где <W extends Foo>
;затем все остальное работает естественным образом.
В Java 7 вывод типов распространяется на конструкторы с <>
синтаксисом
List<? extends Foo> fooList = ...;
DataModel<? extends Foo> model = new ListDataModel<>(fooList); // OK in Java 7
С <>
вызов конструктора во многом аналогичен методузвонки;так что make()
больше не нужен.До Java 7 требовались статические фабричные методы, такие как make()
, чтобы исправить проблему, заключающуюся в том, что конструкторы не делают вывод.Эта практика устарела.