Foo<Double> f = new Foo<Double>();
Когда вы используете эту версию универсального класса Foo, тогда для переменной-члена a
компилятор по существу принимает эту строку:
private T[] a = (T[]) new Object[5];
и замену T
на Double
, чтобы получить:
private Double[] a = (Double[]) new Object[5];
Нельзя приводить от Object к Double, следовательно, ClassCastException.
Обновление и уточнение: На самом деле, после запуска некоторого тестового кода, ClassCastException является более тонким, чем этот. Например, этот основной метод будет работать без каких-либо исключений:
public static void main(String[] args) {
Foo<Double> f = new Foo<Double>();
System.out.println(f.getA());
}
Проблема возникает при попытке присвоить f.getA()
ссылку типа Double[]
:
public static void main(String[] args) {
Foo<Double> f = new Foo<Double>();
Double[] a2 = f.getA(); // throws ClassCastException
System.out.println(a2);
}
Это связано с тем, что информация о типе переменной-члена a
стирается во время выполнения. Обобщения обеспечивают безопасность типов только во время компиляции (я как-то игнорировал это в своем первоначальном посте). Так что проблема не в
private T[] a = (T[]) new Object[5];
потому что во время выполнения этот код действительно
private Object[] a = new Object[5];
Проблема возникает, когда результат метода getA()
, который во время выполнения фактически возвращает Object[]
, присваивается ссылке типа Double[]
- этот оператор генерирует исключение ClassCastException, поскольку Object не может быть приведен к Double.
Обновление 2 : чтобы ответить на ваш последний вопрос "почему массивы ломают это?" Ответ в том, что спецификация языка не поддерживает создание универсального массива. См. Это сообщение на форуме для получения дополнительной информации - для обеспечения обратной совместимости ничего не известно о типе T во время выполнения.