Как было сказано
ранее, массивы в Java ковариантны. А значит, можно обратиться к объекту типа
String[]
через переменную типа
Object[]
, и положить туда например
Integer
. Такой код скомпилируется, но в момент записи произойдет
ArrayStoreException
.
Дженерики защищены инвариантностью. Если попытаться положить
List<String>
в переменную
List<Object>
, эта же по сути ошибка произойдет уже на этапе компиляции.
Heap pollution – ситуация, когда эта защита не срабатывает, и переменная параметризованного типа хранит в себе объект, параметризованный другим типом. Простейший пример:
List<String> strings = (List) new ArrayList<Integer>();
Документация
гарантирует, что при компиляции
всего кода целиком, heap pollution
не может возникнуть без варнинга этапа компиляции.
Heap pollution может произойти в двух случаях: при использовании массивов дженериков и при смешивании параметризованных и raw-типов.
Raw types – это параметризованные типы без указания параметра. Пример с raw types, приводящий к heap pollution, уже был описан выше. Использовать raw types не надо вообще, причины подробно изложены в главе 26
Effective Java. Если информация о дженериках не нужна, используется символ wildcard (<?>).
Компилятор не даст создать массив параметризованного типа, это приведет к ошибке
generic array creation. Картинка ниже иллюстрирует, к чему это могло бы привести.
Параметризованный тип varargs-аргумента метода вызывает ту же проблему, т.к. varargs – не что иное как параметр-массив. Вот почему он так же приводит к предупреждению компилятора «possible heap pollution». Если вы уверены что риска нет, с Java 7 это предупреждение заглушается аннотацией
@SafeVarargs
.