Почему коллекция заданная как может принять в себя Double, в то время как не может?

Коллеги, такой код у меня работает:

 ArrayList<? super Number> arL = new ArrayList<>(); //Ограничение снизу
        arL.add(23.3f);
        arL.add(23d);
        arL.add(32);
        for(Object o : arL){
            System.out.println(o + " " + o.getClass());
        }

Output:

23.3 class java.lang.Float

23.0 class java.lang.Double

32 class java.lang.Integer

А код, который ограничивает сверху добавляемые типы - не работает.

ArrayList<? extends Number> arL = new ArrayList<>(); //Ограничение сверху
        arL.add(23.3f);
        arL.add(23d);
        arL.add(32);
        for(Object o : arL){
            System.out.println(o + " " + o.getClass());
        }

Я проверил на независимом ресурсе - компилятор там тоже заругался на второй код и съел легко первый. Запись <? extends Number> я понимаю как "прими в коллекцию Number и\или его подтипы". Integer, Double и Float унаследованы от Number. Значит они должны лететь в эту коллекцию (№2) легко и непринужденно. С другой стороны <? super Number> я понимаю как "прими в коллекцию Number и\или его супертипы". Но Double, Float и Integer не являются супертипами по отношению к Number. Понятное дело, что при добавлении этих переменных в коллекцию №1 должна появится ошибка компилляции. Её - нет. То есть, компилятор ведет себя с точностью наоборот.

Вопрос: чем объясняется наблюдаемое поведение?


Ответы (1 шт):

Автор решения: StateItPrimitive

К сожалению, это нетривиальные особенности wildcard дженериков в Java:

  1. wildcard ? extends позволяют только читать из коллекции (но не писать в неё), отличие от wildcard ? super;
  2. wildcard ? super позволяет только писать в коллекцию (но не читать из неё), в отличие от wildcard ? extends.

Таким образом, из одного типа wildcard можно только читать, а в другой можно только писать. Исключением является возможность записи null в ? extends и возможность чтения Object из ? super.

Подробнее смотрите здесь.

→ Ссылка