Could you please explain me how the casting works ( in memory )?
It works at byte code level not really in memory
How the variable type is changed on upcasting and downcasting?
If it is a primitive with an special bytecode instruction, for instance from long to integer as in:
long l = ...
int i = ( int ) l;
The bytecode is: l2i
if is a reference with the instruction checkcast
How the JVM knows that from this time it's safe to send this method to this object?
It doesn't, it tries to do it at runtime and if it fails throws an exception.
It is legal to write:
String s = ( String ) new Date();