На уровне виртуальной машины это происходит потому, что примитивные типы представляются в памяти очень по-разному по сравнению с ссылочными типами, такими как java.lang.Object и его производные типы. Примитив int в Java, например, занимает всего 4 байта в памяти, тогда как объект занимает минимум 8 байтов сам по себе, плюс еще 4 байта для ссылки на него. Такая конструкция является простым отражением того факта, что процессоры могут гораздо эффективнее обрабатывать примитивные типы.
Таким образом, один из ответов на ваш вопрос «зачем нужны типы оболочек» связан с улучшением производительности, которое он обеспечивает.
Но для программистов такое различие добавляет некоторые нежелательные когнитивные издержки (например, нельзя использовать int и float в коллекциях.) На самом деле, вполне возможно создать языковой дизайн, скрыв это различие - многие языки сценариев это, и CLR делает это. Начиная с 1.5, Java тоже это делает. Это достигается за счет того, что компилятор может молча вставлять необходимое преобразование между примитивным представлением и представлением объекта (которое обычно называют боксом / распаковкой).
Итак, еще один ответ на ваш вопрос: «Нет, нам это не нужно», потому что компилятор делает это автоматически для вас, и в определенной степени вы можете забыть, что происходит за кулисами.