Ответ 1
Потому что так работают дженерики. Не забывайте, что перед дженериками, когда вы объявили List
, это был список Object
. Ожидалось, что вы станете/получите Object
, и вас заставили бросить, чтобы получить ваш объект с правильным типом. На самом деле это все еще есть список Object
во время выполнения.
Generics - это способ для компилятора гарантировать, что вы вводите безопасность во время компиляции, если у вас нет предупреждений. Во время выполнения нет List<String>
. Существует только List
. Компилятор ставит для вас автоматический выбор, поэтому вы можете в своем коде писать String s = list.get(i)
без кастования.
Когда вы объявляете GenericClass a
, вы объявляете необработанный тип (вы должны получить предупреждение об этом), поэтому компилятор не имеет способа узнать, какой тип должен возвращаться a.getList()
. Поэтому он использует Object
. Когда вы объявляете GenericClass<Number> a = null;
, теперь компилятор знает, какого типа ожидать для a.getList()
и использует желаемый.
Изменить: Следует уточнить, что компилятор может знать, чего ожидать, только если вы соблюдаете контракт подписи (т.е. как в случае с GenericClass<Number>
). Если вы не соблюдаете договор (т.е. Используете необработанный тип, который не соответствует extends Number
), то контракт больше не применяется. Компилятор ведет себя так, как будто информация о типе не присутствует. Не забывайте, что компилятор также должен поддерживать обратную совместимость с кодом, который был создан в эпоху до генериков.