Why does casting from HashMap to Integer runs with no error?
You're not casting from a HashMap to Integer. You're casting an auto-boxed int to an Integer.
x = (Integer) 1234;
1234 is an int literal which is auto-boxed into an Integer when you try to use it as a reference type.
You then return that Integer and get a ClassCastException because it cannot be cast to a HashMap.
return x;
returns 1234, and this is then cast here
(HashMap<String,String>) f(before)
which fails.
Maybe there's a conceptual error here.
Object x defines a box that can hold a reference to any type of object.
f(myHashMap) starts a function call that fills the box x with a reference to a hash map.
x = (Integer) 1234 throws out the contents of the box and replaces it with a reference to an Integer. This is legal because the declaration Object x establishes that that box can contain a reference to any object (or none:null).
You then return x from f whose return type is Object and use it here
HashMap<String, String> after = (HashMap<String, String>) f(before)
which is taking the contents of a box that can contain anything, and making sure that it can fit in a box named after that can only contain HashMap<?,?>s.
That doesn't work, because the reference returned by f(before) does not fit in that box. Hence the exception at runtime.
You can reduce your program to the below to understand what's going on.
Object x = (Integer) Integer.valueOf(1234); // Unnecessary cast.
HashMap<String, String> m = (HashMap<String, String>) x; // Fails due to type-unsafe cast.
and if you eliminate the use of Object, you will probably get the problem explained to you by the compiler
Integer x = (Integer) Integer.valueOf(1234);
HashMap<String, String> m = (HashMap<String, String>) x;