Почему генерические средства Java не допускают преобразование типов в общие типы?
public class Main {
public static <T> void foo(T[] bar) {
double d = (double) bar[0]; // Error : incompatible types
}
public static void main(String[] args) {
int[] int_buf = new int[8];
foo(int_buf);
}
}
Проблема указывается в коде.
Почему дженерики Java не допускают преобразование типов в общие типы?
Ответы
Ответ 1
Это связано с тем, что вы не указываете, что такое общий тип T
. Поэтому по умолчанию он будет думать, что T - тип объекта, а не число. Невозможно подвергнуть объект двойному, это не имеет смысла.
Если вы переходите на <T extends Number>
, это должно работать нормально. Хотя, возможно, вам понадобится массив Integer, а не массив int
Ответ 2
Проблема глубже, чем это. Даже без выделенной строки эта программа не работает:
public class Main {
public static <T> void foo(T[] bar) {
// do nothing
}
public static void main(String[] args) {
int[] int_buf = new int[8];
foo(int_buf); <-- problem is here
}
}
Генераторы Java поддерживают только ссылочные типы как параметры типа; общий метод foo() можно переписать следующим образом:
<T extends Object> void foo(T[] bar) { ... }
И вот ваша проблема: нет T
, которая расширяет Object
таким образом, что int[]
является T[]
.
Во-вторых, причина, по которой конверсия также терпит неудачу, заключается в том, что мы ничего не знаем о T
, поэтому мы не знаем, что существует преобразование от T
до double
.
Ответ 3
Компилятор Java стирает все параметры типа в общем коде. Прямым следствием этого является то, что вы не можете проверить, какой параметризованный тип для общего в настоящее время используется. Если вы проверите, instanceof
тоже не будет работать. Так как runtime не отслеживает параметры типа в java, нет разницы между HashSet<Integer>
и HashSet<Double>
. Вы можете сделать ..instanceof HashSet<?>
максимум, чтобы проверить, является ли это экземпляром HashSet.
Если что-то непонятно в том, что я написал, обратитесь к docs.