Кастование числа к строке не кидает ClassCastExeption при использовании дженериков - почему?

1,00
р.
Объясните, пожалуйста, почему в строчке //(?!) не выбрасывается исключение ClassCastExeption? Там стоит (T), где T=String, а значит там (String) new Integer(42), что должно давать исключение... JVM должна привести тип, но почему-то она этого не делает. Дальше мы смотрим тип t и видим Integer, что действительно является реальным типом t. Но факт того, что мы вывели тип, показывает: исключение не создалось. Потом программа выбрасывает исключение там, где была вызвана функция A.f().
Кстати! Помнится мне, Bruce Eckel учит тому, что существует некоторый декомпилятор javap, он сам пишет код программы то ли из байт-кода, то ли из .class... Не изучал. Если кто сведущ в этом, попробуйте заставить декомпилятор построить этот кусок кода, может он покажет, что там происходит на самом деле, и почему?
public class A { public static T f() { T t = (T) new Integer(42) // (?!) ЧТО ЧЁРТ ВОЗЬМИ ЗДЕСЬ ВООБЩЕ ПРОИСХОДИТ?! System.out.println(t.getClass()) return t }
public static void main(String[] args) { System.out.println(A.f()) // как здесь возможно исключение? ахаха, вы серьёзно? } }
Новое: Итак, друзья. Самым частым ответом стало: метод f() -- это обычный метод, который компильнулся как обычный, но с учётом того, что результаты его вызовов приводятся к типу, передаваемому как . Вроде бы уже всё хорошо, и можно принять такой ответ, но если бы оно правда так работало в Java... Дело в том, что можно в main(String[]) попытаться вызвать кое что ещё более взрывное:
System.out.println(A.f())
Удивительно, но в консоли выйдет:
//output: class java.lang.Integer 42
Так вот если у нас невидимо это выглядит так:
System.out.println((Double)A.f())
То попробуйте это компильнуть -- выйдет ошибка ахахахха, от куда вывод, что всё таки работает оно не так...
Мои догадки на этот счёт таковы, что метод println() перегружен, и в случае A.f() он выбирал версию println(String arg), а в случае A.f() он понимал, что Double версии нет и ставил println(Object arg) из-за чего, для нашего (Object)Integer(42) вызывалось .toString() и выводилось 42.
Для меня здесь странно то, что почему-то в первом случае, когда мы вызывали A.f() он, как многие здесь считают вызывал это так (String)A.f(), от куда ставил версию println(String arg), а во второй раз, при вызове A.f() он не попытался сделать так (Double)A.f(), он сразу выбрал println(Object arg)...
Хотите сказать, что вся технология такая умная, что если возврат параметризованной/обобщённой функции проверяется на существование как аргумент в перегруженном методе println() с успехом, то приведение не вызывается [например String версия println() существует, ага, приведём выходной Object от A.f() к указанному String], а если перегруженной версии с указанным в типе-параметре для A.f() классом версии println() нет, то он (компилятор) оставляет версию println(Object) и решает не пытаться даже сделать (Object)(Double)A.f(), где сам результат f() есть Object ?
Итого: Я хочу объяснения принципа работы параметризованных методов (классов), такое объяснение, чтобы был точно понятен алгоритм действий компилятора для создаваемого кода. Если какие-то мои догадки на счёт действий компилятора верны, то я хочу их (моих догадок) подтверждения и очень желательно (!) с ссылкой на какие-нибудь документационные файлы!

Ответ
Типов у генериков не существует в рантайме. Это просто проверки при компиляции.
public static T f() {

public static Object f() {
T t = (T) new Integer(42) // (?!) ЧТО ЧЁРТ ВОЗЬМИ ЗДЕСЬ ВООБЩЕ ПРОИСХОДИТ?!

Object t = (Object) new Integer(42) // всё хорошо
return t

По-прежнему всё хорошо. Object.
System.out.println(A.f()) // как здесь возможно исключение? ахаха, вы серьёзно?

System.out.println((String)f())
Упс.. Там не String. Вот и исключение.

Получается такая штука:
(String) (Object) new Integer(42) ^^^^^^^^------------------ Integer - наследник Object ^^^^^^^^--------------------------- String - наследник Object
Ошибки при компиляции нет, а при выполнении первое преобразование оказывается в f и оно валидно, а вот второе - уже в main, где оно и валится.