
В качестве Type могут выступать классы, интерфейсы и enum. Если в качестве ограничивающего типа выступает интерфейс, для него всё равно используется ключевое слово "extends".
List<? extends Number> listInt = new ArrayList<Integer>();
List<? extends Number> listDouble = new ArrayList<Double>();
List<? extends Number> listStr = new ArrayList<String>(); // ошибка компиляции
Внимание! Через ссылочные переменные, ограниченные сверху, нельзя добавлять новые элементы! Поскольку список создаётся для хранения конкретного типа объектов, то компилятор не уверен, что тип добавляемого объекта именно тот, для которого этот список был создан.
listInt.add(new Integer(10)); // ошибка компиляции
Метод add() принимает всех наследников Number. Для компилятора передаваемый объект будет просто каким-то наследником без конкретного типа. Integer - наследник Number. Но и Double тоже наследник Number. Объект типа Double нельзя передать в список типа Integer. Поэтому запрещено добавление объектов через ссылки, ограниченные сверху.