Double a = ((TypeList<Double>)list).getData(); //Fails at runTime
Это суть вашего вопроса. Переменная list на самом деле является TypeList<Dummy>
. Компилятор знает это и сгенерировал ошибку во время компиляции, когда вы написали
Double a = list.getData();
Безопасность во время компиляции на работе там. Но вы применили приведение к компиляции. Компилятор работает исходя из предположения: «он знает, что делает, он использовал приведение» и позволяет ему пройти. Конечно, работать не будет, теперь он бомбит во время выполнения.
Вы могли бы возразить, "но компилятор знает , что приведение не может работать, разве это не безопасность типов?" Нет, приведение очень мощное, оно позволяет вам переопределить то, что знает компилятор. Этот конкретный пример не очень хороший, но вы должны использовать приведение для преобразования ссылки на базовый класс, например, в ссылку на производный класс. Довольно часто. Сила броска - это то, что делает его опасным. Большим преимуществом дженериков является то, что вам не нужно их использовать.