Если вам нужно действительно техническое объяснение, я бы порекомендовал прочитать эти слайды в программном обеспечении на основе компонентов , чтобы получить полную картину проблемы, поскольку ваша маленькая проблема имеет огромные последствия в больших масштабах :)
Реальные условия: контравариантность и ковариация . Ищите их в этих слайдах относительно ОО-дизайна и его ограничений в больших системах.
Ваша проблема в том, что они смешаны с некоторыми генериками , смешанными в:)
То есть, ваш контракт ( что-то, что является фруктом чего-то более специфичного, чем фрукт * ) указывает, что список должен содержать всех видов фруктов, но вы создаете список, способный содержать только определенный вид фруктов ( яблоки или что-то более конкретное, чем яблоко ), что, по моему мнению, должно вызывать ошибку компиляции, но Java-компилятор слишком хорош и Обобщения не реализованы должным образом в Java (семантически и с точки зрения самоанализа).
Экземпляр контейнера может быть ковариантным или инвариантным по отношению к типу / классу контейнера, но лицо, являющееся экземпляром, должно быть инвариантом по отношению к типу / классу контейнера.
Конкретный пример:
List<Fruit> list = new ArrayList<Fruit>();
Общий пример:
ConatainerType<ElementOfList> list = new MoreSpecificContainerType<ElementOfList>();
ElementOfList должен выполнять как ковариацию, так и контравариантность, поскольку объекты могут быть как помещены (ковариация), так и извлечены (контравариантность), что оставляет только инвариантность, то есть тот же тип / класс.
Это был действительно длинный ответ, но я надеюсь, что он поможет кому-то, кто задаст подобный вопрос в будущем.