Компилятор не достаточно умен, чтобы знать, что objFoo1
действительно прост Foo1
. Он не анализирует ваш исходный код достаточно глубоко, чтобы определить это. Все, что он видит, это то, что objFoo1
является Foo1
, Foo2
является производным от Foo1
, и поэтому приведение является законным. Если вместо этого вы измените это значение на (int) objFoo1
, оно будет бомбить во время компиляции, так как компилятор может увидеть, что нет никакого способа превратить Foo1
в целое число.
Представьте, что между этими двумя объявлениями было 1000 строк кода, многие из которых выполняли различные присваивания objFoo1
. Компилятору придется проделать большую тяжелую работу, чтобы попытаться определить, какой именно объект находится в objFoo1
. В общем, это не всегда можно сделать. Компилятору гораздо проще просто взять статическую информацию о типе по номиналу и предположить, что objFoo1
- это некоторый тип объекта Foo1
, но не более. Таким образом, она не отвергает вашу простую тестовую программу, но принимает более сложную.
В этом случае компилятор также не должен отклонять ваш код. Возможно, хотя и заведомо надуманным, что вы намеренно пытаетесь сгенерировать ClassCastException
, выполняя незаконное приведение. Это было бы необычно, но не противозаконно.
Вдобавок к этому есть и другие случаи, когда статический анализ кода компилятора можно обмануть. Это не удастся скомпилировать:
return;
System.out.println("hello world!"); // compile error - unreachable code
Хотя это скомпилируется нормально, хотя семантически идентично:
if (true) return;
System.out.println("hello world!");