Можно чуть подробнее про невозможность следующего кода: if(iOb instanceof Gen)
Я слышал, что во время рантайма все дженерики преобразуются к обычным типам. Я не до конца понимаю, как это происходит, возможно поэтому и не понимаю, почему следующий код вызывает ошибку компиляции:
class Gen<T> {
T ob;
Gen(T o) {
ob = o;
}
}
public class GenHierarchy {
public static void main(String args[]) {
Gen<Integer> iOb = new Gen<Integer>(88);
if (iOb instanceof Gen<Integer>)
System.out.println("iOb2 is instance of Gen2<Integer>");
}
}
Я полагал, что как раз-таки после удаления сведений о том, что класс Gen обобщенный, мы получим простейший случай необобщенного класса и его экземпляра. Мне кажется JVM должно быть еще понятнее. Понимаю, что ошибаюсь. Но не понимаю, из-за чего реально проблема. Почему такую элементарную на первый взгляд зависимость в рантайме нельзя проверить?
Ответы (1 шт):
Информация о параметре обобщенного типы действительно стирается во время исполнения. Это значит, что код который сгенерирует компилятор (не считая проверки, которая синтаксически некорректная, но об этом дальше) будет таким:
class Gen {
Object ob;
Gen(Object o) {
ob = o;
}
}
public class GenHierarchy {
public static void main(String args[]) {
Gen iOb = new Gen(88);
...
}
}
На этапе компиляции, компилятор дополнительно проверит, что в выражении new Gen(88) аргумент может быть приведен к параметру указанному вместо T, т.е. к Integer. Именно это суть обобщенных типов - компилятор делает дополнительную проверку, в данном случае, что вы в программе используете объект типа совместимого с типом generic-a. И если в программе использующей обобщенные типы нет ни одного предупреждения компилятора, то гарантируется, что во время исполнения вы никогда не получите ClassCastException.
Во время же выполнения, если посмотрите на код выше, нет никакой информации о том, что реально хранится в iOb. Можно возразить "есть же поле ob" - но в общем случае это не работает, т.к. у вас необязательно будет поле с типом параметра generic-а, или в таком поле, даже если оно есть, может храниться null, и тогда опять же реальный тип взять неоткуда.
Более того, путем явного приведения типов и игнорирования предупреждений компилятора, вы можете в iOb засунуть любой тип:
Gen<Integer> iOb = new Gen<Integer>(88);
((Gen)iOb).ob = new String("aaa");
Именно поэтому, проверка так как вы ее хотите написать iOb instanceof Gen<Integer> не имеет смысла, и является синтаксически неправильной.
Проверять можно либо так iOb instaceof Gen, либо так iOb.ob instanceOf Integer.