Вы правы в том, что ваш последний фрагмент кода на самом деле не опасен (хотя он генерирует предупреждение компилятора).
Причина, по которой использование необработанных типов потенциально опасно, заключается в том, что вы теряете безопасность типов, которую обеспечивают дженерики. В частности, вы теряете гарантию того, что вы не можете рассматривать «универсальный параметр» как два разных типа в двух разных сценариях. (Вот в чем проблема в вашем примере приведения к строке - считается, что список содержит целые числа в одна точка (при заполнении), но считается, что она содержит строки в другой точке).
В последнем примере, который вы предоставили, предупреждение является технически ложным, поскольку на построенный необработанный список можно ссылаться только по ссылке ali
, которая правильно введена. Поэтому было бы невозможно вставить строки в него.
Однако компилятор не может гарантировать это в целом, поскольку это деталь реализации того, как работает конструктор ArrayList
, который делает это безопасным. (Другая реализация списка может «публиковать» ссылку на себя извне, которая затем может быть использована для вставки элементов неправильного типа в этот список). Компилятор просто видит, что вы присваиваете что-то необработанного типа ArrayList
переменной типа ArrayList<Integer>
, и правильно говорит, что «вещь с правой стороны могла бы использоваться для знаете, в прошлом, кроме целых чисел, вы уверены, что это нормально? " Это примерно эквивалентно
ArrayList al = new ArrayList();
ArrayList<Integer> ali = al;
, где в этом слегка расширенном случае «временная» переменная al
позволяет вызывать al.add("not an int")
без ошибок времени компиляции.
Нет никакой реальной пользы в том, чтобы делать вещи таким образом и «зная», что это правильно, вы также можете составить список с правильными общими параметрами с самого начала, как в первом примере. Неконтролируемые предупреждения о преобразованиях часто не являются реальной проблемой, но могут быть довольно частыми - подавление предупреждений создает риск того, что вы перейдете из первой ситуации во вторую, не заметив этого. Заставить компилятор проверить вас означает, что он может сказать вам, если ваши базовые предположения станут недействительными.