Какая польза от слова <? extends SomeObject> вместо <SomeObject>

Итак, я просматривал Java-код и наткнулся на:

List<? extends SomeObject> l;

в основном этот список принимает все объекты, которые являются своего рода SomeObject - самими SomeObject или его наследниками. Но в соответствии с полимофисом, его наследники также могут восприниматься как SomeObject, поэтому это также сработает:

List<SomeObject> l;

Так почему бы кто-то использовать первый вариант, когда второй четко определен и практически идентичен?

Ответ 1

List<SomeObject> l;

В этом вы не можете сказать List<SomeObject> l = new ArrayList<SubClassOfSomeObjectClass>; (не разрешено) для

List<? extends SomeObject> l;

вы можете сказать

List<? extends SomeObject> l = new ArrayList<SubClassOfSomeObject>; (разрешено)

Но обратите внимание, что в List<? extends SomeObject> l = new ArrayList<SubClassOfSomeObject>; вы не можете добавить что-либо в свой список l, потому что? представляет неизвестный класс (За исключением нулевого курса).

Обновление: Для вашего вопроса в комментарии What could I possibly do with a list if I cannot add anything to it?

Теперь рассмотрим случай, когда вам нужно написать функцию для печати списка, но помните, что он должен принимать только список, содержащий объекты, которые являются подклассами вашего SomeObject. В этом случае, как я сказал выше, вы не можете использовать

public void printList(List<SubClassOfSomeObjectClass> someList)

Итак, что бы вы сделали? Вы бы сделали что-то вроде

    public void printList(List<? extends SomeObject> someList) {
        for(SomeObject myObj : someList) {
             //process read operations on  myObj
        }

Ответ 2

Ключевая ссылка, которую вы хотите прочитать, http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html, которая подробно описывает общий шаблон.

List<SomeObject> не совпадает с List<? extends SomeObject>. Соблюдайте следующее

List<Object> x = new ArrayList<Object>();
List<String> y = new ArrayList<String>();
// x = y; Will throw Compilation exception
List<? extends Object> z = y; //will pass compilation

Возможно, вам захочется заметить, что вы можете добавить строку String как в список x, так и y, но это будет полезно, когда вы пишете, скажем, библиотечную функцию (например, printCollection в примере, показанном в ссылке), а не принимая Collection<Object>, и в этом случае пользователь не может передать свой список строк, которые у него есть для вашего метода, если вы принимаете Collection<? extends Object>, тогда пользователь может передать его Collection<Apple>, Collection<Orange> и т.д., не создавая явно другого списка.

Ответ 3

List<? extends SomeObject> l; не принимает new SomeObject() но List<SomeObject> l; делает.

что тоже не работает: List<SomeObject> l = new ArrayList<SubTypeOfSomeObject>()

что работает: List<? extends SomeObject> l = new ArrayList<SubTypeOfSomeObject>()

Ответ 4

X не может быть добавлен в List<Y>, даже если X можно преобразовать в Y.

Итак, во втором случае, если List<X> l; было разрешено добавлять подкласс X, это разбило бы основной принцип безопасности типов

Ответ 5

В качестве первого ответа

List<? extends SomeObject> l;

должен содержать объект, наследующий от SomeObject, а не некоторый прямой объект SomeObject.