Короткий ответ
Generics — это параметризованные типы: классы, интерфейсы и методы работают с типом, который задаётся при использовании, а не «зашит» в код. Главная решаемая проблема — типобезопасность и раннее обнаружение ошибок: компилятор проверяет типы на этапе компиляции, а не в рантайме, и убирает ручные приведения к Object.
Как это работает подробнее
До дженериков коллекции хранили Object, и при извлечении требовалось явное приведение, например к строке. Если в список по ошибке попал элемент другого типа, программа падала с ClassCastException в рантайме, часто далеко от места добавления. С дженериками неверный тип не проходит компиляцию — проверки выполняются на этапе компиляции.
Механизм работает с классами, интерфейсами и методами: тип-параметр задаётся при использовании (класс с параметром T, дженерик-методы и дженерик-интерфейсы). Параметром может быть только ссылочный тип — примитив нужно оборачивать в класс-обёртку (Integer вместо int). Информация о типе-параметре существует только до компиляции: в рантайме она стирается.
- Коллекция «знает» тип своих элементов: список, параметризованный строкой, не примет число.
- Код становится самодокументируемым и не требует шаблонных приведений типов.
Пример кода
import java.util.ArrayList;
import java.util.List;
public class GenericsDemo {
public static void main(String[] args) {
List<String> words = new ArrayList<>();
words.add("java");
// words.add(42); // не скомпилируется
String first = words.get(0); // без приведения типов
System.out.println(first.toUpperCase());
}
}Что использовать на практике
- Коллекции всегда объявляйте с параметром типа — это включает проверки компилятора.