Помните, что дженерики в Java - это всего лишь время компиляции. Во время выполнения все универсальные c параметры стираются в не универсальные c типы.
С точки зрения компилятора, listStrToListT
может возвращать любой тип List
, который хочет вызывающий, а не только List<String>
. Вы убедили компилятора в этом не факте, сделав (1) listStrToListT
generi c и (2) приведение idStr
к T
. Вы говорите: «Я уверен, что этот актерский состав сработает, когда он запустится. Не волнуйтесь, компилятор! Этот актерский состав, безусловно, пахнет рыбой, не так ли? Что если T
равно A
...
В любом случае, теперь List<A> lst = listStrToListT("1,2,3");
компилируется, так как listStrToListT
"может возвращать любой тип List
", как упоминалось ранее. Вы можете себе представить, что T
подразумевается как A
, и ваше приведение в listStrToListT
завершится неудачно во время выполнения, но это не то, что происходит.
Теперь это время выполнения, все общие c типы стереть, и ваш код будет выглядеть следующим образом:
public static List listStrToListT(String str) {
String[] idStrs = str.replace(" ", "").split(",");
List uids = new ArrayList();
for (String idStr : idStrs) {
uids.add((Object)idStr);
}
return uids;
}
// main method:
List lst = listStrToListT("1,2,3");
System.out.println(lst);
Обратите внимание, что приведение к T
становится приведением к Object
, что на самом деле просто избыточно.
Распечатка список включает в себя вызов toString
для каждого из Object
s, поэтому приведение там не выполняется.
Обратите внимание, что то, что "пахло рыбой" во время компиляции, полностью действует во время компиляции. Рыбный бросок стал совершенно действительным (и избыточным) броском до Object
! Где приведение go?
Приведение будет вставлено только при необходимости. Именно так работают дженерики в Java. Итак, давайте создадим такую ситуацию. Допустим, в A
у вас есть геттер для поля a
, и вместо печати всего списка вы печатаете a
первого элемента:
// main method:
List<A> lst = listStrToListT("1,2,3");
System.out.println(lst.get(0).getA());
Ну, чтобы иметь возможность для доступа к getA
необходимо вставить приведение:
List lst = listStrToListT("1,2,3");
System.out.println(((A)lst.get(0)).getA());
в противном случае lst.get(0)
будет иметь тип Object
, а Object
s не имеет getA
метода.
В это время ваша программа обработает sh.