Этот пример напоминает мне о ранних днях, когда я читал об обобщениях в книге «Эффективная Java» ...
Прежде всего, вот золотое правило java generics: не смешивайте массивы и genericsпотому что у вас есть хороший шанс создать небезопасный код.Ваш код смешивает дженерики (например, T, T расширяет карту) с массивами (например, карты T []).Затем вы получили небезопасный код во время выполнения.
Это один из безопасных способов (предпочтение спискам, а не массивам):
class Deck <T extends Card> {
private List<T> cards;
public Deck () {
cards = new ArrayList()<>;
}
}
Теперь, чтобы ответить на ваш вопрос, высначала вернемся к некоторым основам в java:
1- Массивы являются ко-вариантными конструкциями
2- Дженерики являются инвариантными конструкциями
3- Тип элемента повторно реализован в массивах(reification)
4- Тип параметра стирается в Generic (стирание типа)
Не беспокойтесь, оставьте в стороне страшные понятия и проверьте, что случилось с вашим примером:
Формальный тип T стирается во время выполнения.
Это означает, что он полностью удален в байт-коде.
В первомНапример, T просто заменяется на Object, потому что это ближайший к нему класс (с точки зрения наследования), поэтому
cards = (T []) new Object[52]
переводится в
cards = (Object []) new Object[52];
который является безопасным.
- Во 2-м примере T привязан к Card и, следовательно, становится ближайшим классом to (с точки зрения наследования), поэтому
cards = (T []) new Object[52]
переводится в
cards = (Card []) new Object[52];
Поскольку Object не является подтипом Card, вы получили исключение приведения во время выполнения.