Почему коллекция заданная как super Number> может принять в себя Double, в то время как extends Number> не может?
Коллеги, такой код у меня работает:
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 шт):
К сожалению, это нетривиальные особенности wildcard дженериков в Java:
- wildcard
? extendsпозволяют только читать из коллекции (но не писать в неё), отличие от wildcard? super; - wildcard
? superпозволяет только писать в коллекцию (но не читать из неё), в отличие от wildcard? extends.
Таким образом, из одного типа wildcard можно только читать, а в другой можно только писать.
Исключением является возможность записи null в ? extends и возможность чтения Object из ? super.
Подробнее смотрите здесь.