Какую проблему на самом деле решили дженерики в Java

Вопрос звучит как разминочный, но проверяет не память, а понимание — многие отвечают «добавили типобезопасность» и на этом останавливаются, хотя суть глубже.

До Java 5 коллекции хранили Object. Это значило, что при чтении элемента нужно было вручную привести тип: String s = (String) list.get(0). Если кто-то в этот же список случайно положил Integer, компилятор молчал — ошибка проявлялась в рантайме как ClassCastException, причём не в момент записи неправильного элемента, а гораздо позже, в момент чтения, часто в совсем другом месте кода.

List list = new ArrayList(); list.add("hello"); list.add(42); // компилируется без ошибок

String s = (String) list.get(1); // ClassCastException здесь, а не там, где добавили 42

Дженерики перенесли эту проверку на этап компиляции. List не позволит добавить Integer — ошибка всплывёт там, где её совершили, а не там, где она случайно обнаружилась.

Следом почти всегда спрашивают про стирание типов (type erasure): в рантайме List и List — это один и тот же класс List, информация о параметре типа не сохраняется в байткоде. Отсюда растут вопросы про невозможность new T(), создание массива дженерик-типа и причину, по которой instanceof с параметризованным типом не компилируется.

Дженерики — это про момент обнаружения ошибки, а не про производительность или красоту кода. Сдвиг с рантайма на компиляцию и есть причина, зачем их вводили.

senior·base — что спрашивают на самом деле


В этом посте были ссылки, но мы их удалили по правилам Сетки