2015-01-21 1 views
2

Учитывая следующую структуру класса:Почему этот список не генерирует исключение ClassCastException?

class Animal {} 
class Dog extends Animal {} 
class Cat extends Animal {} 

И создать список, используя дженерики только на инициализацию и не по ссылке:

List dogs = new ArrayList<Dog>(); 

Почему этот код генерировать ClassCastException?

dogs.add(new Cat()); // How is Cat casted to Dog??! 
Cat cat = (Cat) dogs.get(0); // Return perfectly valid Cat object. 

Я понимаю, что не будет никакой ошибки компиляции, поскольку list ссылка не имеет каких-либо обобщений и будет принимать какие-либо Object. Но почему JVM генерирует какое-либо исключение, когда я пытаюсь добавить объект Cat?

+4

Дженерики стираются во время выполнения. Дженерики - это функция компиляции. Поскольку, как вы сказали, ваш список является сырым списком, в который вы можете добавить любой объект. _ «Я понимаю, что ошибки компиляции не будет, так как ссылка на список не содержит никаких дженериков», - сказал он. Вы добавляете кошку, а затем получаете кота с индексом 0. – user2336315

ответ

2

Переменная dogs имеет тип List, который является необработанным типа. Это не типа List<Dog>.

И поскольку это сырой тип, вы можете добавить к нему любой объект. Ваш экземпляр Cat не накладывается ни на что.

Generics предоставляет только безопасность и проверку во время компиляции, они не используются во время выполнения.

Подробнее о необработанных типах в Java Language Specification 4.8. Raw Types.

+0

Но список инициализируется объектом типа List , не должен ли это выкидывать любое исключение? – Suyash

+0

Список инициализируется объектом типа 'List'. Только компилятор знает, что статический тип выражения создания экземпляра был «List ». Это никоим образом не отражается во время выполнения. –

+0

@Suyash Нет, потому что общий тип - это просто проверка типа компиляции, во время выполнения нет разницы между «List » и «List ». То, что вы получаете, - это просто предупреждение времени компиляции для использования raw-типа. – icza

1

Для компилятора List dogs эквивалентен List<Object> dogs, поэтому компилятор принимает добавления экземпляров любого типа.

Обратите внимание, что тип списка рассматривается компилятором является исходным типом List (типа локальной переменной на левой стороне задания), даже если правая часть создает экземпляр общего типа с параметром Dog.

0

Дженерики не сохраняются во время выполнения. Таким образом, ArrayList<Dog> - это всего лишь ArrayList. Вот почему во время выполнения исключение нельзя исключить. Компилятор мог поймать эту ошибку во время компиляции, если вы не использовали необработанный тип List.